https://www.hackerrank.com/challenges/occupations/problem?isFullScreen=true
Occupations | HackerRank
Pivot the Occupation column so the Name of each person in OCCUPATIONS is displayed underneath their respective Occupation.
www.hackerrank.com
set @d=0, @p=0, @s=0, @a=0;
select min(doctor), min(professor), min(singer), min(actor)
from(select
case when occupation="Doctor" then name end as Doctor,
case when occupation="Professor" then name end as Professor,
case when occupation="Singer" then name end as Singer,
case when occupation="Actor" then name end Actor,
case
when occupation="Doctor" then (@d:=@d+1)
when occupation="professor" then (@p:=@p+1)
when occupation="singer" then (@s:=@s+1)
when occupation="actor" then (@a:=@a+1)
end as rn
from occupations
order by name) sub
group by rn
이 문제는 공부하고 나면 아하!! 하고 손뼉을 치는 문제다.
일단 내가 헤맸던 이유는... case를 쓰는 건 알겠고 뭔가 partition by를 써야할 거 같은데... 감이 안잡혔다.
일단 위의 코드는 partition by를 안쓰고 변수 선언을 이용한 코드이다.
select
case when occupation="Doctor" then name end as Doctor,
case when occupation="Professor" then name end as Professor,
case when occupation="Singer" then name end as Singer,
case when occupation="Actor" then name end Actor,
case
when occupation="Doctor" then (@d:=@d+1)
when occupation="professor" then (@p:=@p+1)
when occupation="singer" then (@s:=@s+1)
when occupation="actor" then (@a:=@a+1)
end as rn
from occupations
order by name
안에 있는 서브쿼리를 먼저 보면,
직업이 'Doctor'인 사람들의 이름은 'Doctor' 열 안에,
직업이 'Professor'인 사람들의 이름은 'Professor 열 안에,
직업이 'Singer'인 사람들의 이름은 'Singer' 열 안에,
직업이 'Actor'인 사람들의 이름은 'Actor' 열 안에 넣어준다.
그리고 각 직업별로 이름이 나올 때마다 rn을 업데이트해준다.
이렇게 말이다! (행 이름은 Doctor, Professor, Singer, Actor, rn 순이다.)
예를 들면, 네 번째 줄의 Britney는 Professor 열에서 Ashely 다음으로 2번째로 등장했기 때문에 rn은 2가 된다.
이렇게 rn을 출력한 후, 이름순으로 정렬을 해준다.
그리고 rn으로 group by를 해주고 select에 각 열의 최솟값(min)을 넣어주면 null이 밑으로 가고 이름이 올라오게 된다(min 대신 max를 써도 된다.)
이미 서브쿼리에서 이름순으로 정렬을 해줬기 때문에 알파벳 순으로 이름이 정렬이 되고, 그 밑에 null로 채워지게 된다.
이렇게 말이다!
이 방법 외에 partition by를 쓴 다른 사람의 풀이도 찾아봤다.
SELECT
MIN(CASE WHEN OCCUPATION = 'DOCTOR' THEN NAME ELSE NULL END) ,
MIN(CASE WHEN OCCUPATION = 'PROFESSOR' THEN NAME ELSE NULL END) ,
MIN(CASE WHEN OCCUPATION = 'SINGER' THEN NAME ELSE NULL END) ,
MIN(CASE WHEN OCCUPATION = 'ACTOR' THEN NAME ELSE NULL END)
FROM (SELECT OCCUPATION, NAME, ROW_NUMBER() OVER (PARTITION BY OCCUPATION ORDER BY NAME) rn FROM OCCUPATIONS) as tmp
GROUP BY tmp.rn
출처 : https://jogrammer.tistory.com/248
역시 서브쿼리를 먼저 살펴보면,
SELECT OCCUPATION, NAME, ROW_NUMBER() OVER (PARTITION BY OCCUPATION ORDER BY NAME)
FROM OCCUPATIONS
이런식으로 나온다. partition by occupation이라고 했으니 직업별로 row number가 매겨지는 것이다.
그리고 첫 번째 방법과 마찬가지로 row number(rn)를 기준으로 group by를 해준 후 각 rn별 이름의 최솟값을 구해주면 된다.
이 문제는 내가 어려워하는 것들을 다시 짚을 수 있었던 좋은 문제인 것 같다!
'SQL > HackerRank' 카테고리의 다른 글
[해커랭크 medium] New Companies(MySQL) (0) | 2022.03.22 |
---|---|
[해커랭크 medium] Binary Tree Nodes(MySQL) (0) | 2022.03.21 |
[해커랭크 medium] SQL Project Planning(카테시안 곱)(MySQL) (0) | 2022.03.16 |
[해커랭크 easy] The Blunder(다양한 문자열 함수)(MySQL) (0) | 2022.03.16 |
[해커랭크 easy] Weather Observation Station 17(MySQL) (0) | 2022.03.16 |