본문 바로가기
DataBase

[HackerRank] Ollivander's Inventory

by 작심평생 2020. 7. 12.
문제 출처
 
 

 
 
문제 / 조건
  • 최소 금액으로 non-evil면서 높은 power와 age인 지팡이를 찾아라
  • id, age, coin_needed, power를 뽑고 power 내림차순,  이때 동일한 power는 age 내림차순
 
 
문제와 조건을 확인하고 Sample Output과 이에대한 Explanation을 확인했다.
 
 
접근을 어떻게 하면 될까 고민하고 하다가
'code로 join을 걸고 is_evil = 0인 항목으로 추리고 그룹지으면 되겠다'
라고 생각했고 이때부터 늪에 빠지기 시작했다(...) 
 
GROUP BY, HAVING, CASE ...등등 생각했지만 어딘지 모르게
빼먹은 느낌이 들었고 어디서 잘못된건지 고민하다가 GROUP BY부터 잘못된거 아닐까 생각이 들었다.
 
Sample Ouput을 보면 각 코드마다 한줄로 가성비 좋은 지팡이를 뽑는게 아닌
코드에서 해당 age의 해당 power에서 최고의 가성비 제품을 하나씩 뽑아야하는 것이다.
 
즉, 동일한 age, 동일한 power인 경우가 복수개일때 가장 적은 coin_needed인 지팡이를 뽑아야 한다.
 
그래서 윈도우 함수인 PARTITION BY를 써야할 것 같았다.
윈도우 함수 관련 내용은 구루비에서 확인할 수 있다.
 
 
평소 업무를 하면서 PARTITION BY를 쓴적은 없고 DB관련 서적으로
공부할때만 알던 거라 굉장히 낯설었다..
 
GROUP BY는 데이터를 그룹화해서 하나의 ROW로 집약시켜주는데
PARTITION BY는 구역을 나눠주기만 한다. 이게 포인트라고 생각한다.
 
결국 이 문제도 코드별, power별로 구역을 나누고 그 구역에서 최소의 필요금액을 구해야하기 때문이다.
그래서 다른 집계함수대신 ROW_NUMBER를 통해 순서를 줬다.
 
이렇게 하면 위의 그림을 예로 설명하면
age가 45에 power가 10인데 coin_needed가 1000인 데이터가 하나 더 있었다면
기존의 power가 10인 데이터는 ROW_NUMBER가 2가 될것이다. 그렇다면
WHERE 조건으로 ROW_NUMBER가 1인 데이터들만 모으면 된다.
 
 
정답쿼리
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
SELECT
    Q.id,
    Q.age,
    Q.coins_needed,
    Q.power
FROM (
        SELECT
            ROW_NUMBER() OVER(PARTITION BY B.age, A.power order by A.coins_needed) rnum,
            A.id,
            B.age,
            A.coins_needed,
            A.power
        FROM Wands A, Wands_Property B
        WHERE A.code = B.code AND B.is_evil = 0
     ) Q
WHERE Q.rnum = 1
ORDER BY Q.power DESC, Q.age DESC;
 
 
후기
 
PARTITION BY를 쓸 생각은 했지만 실제로 나뉘어지는 모습이나
이를 쓰기위한 윈도우 함수 등 우여곡절이 많았다(...)  + Disscusion에서 다른 분들의 쿼리를 보기도 했다..
쿼리를 어떻게 구현할지 생각하는 것에 더..익숙해지도록 해야겠다..!
 

댓글