본문 바로가기

코딩일기

SQL 코드카타 174 - Challenges

https://www.hackerrank.com/challenges/challenges/problem?isFullScreen=true

 

Challenges | HackerRank

Print the total number of challenges created by hackers.

www.hackerrank.com

 

Column Type
hacker_id Integer
name Integer

 

Hackers테이블:

  • hacker_id : 해커의 id
  • name : 해커의 이름

 

Column Type
challenge_id Integer
hacker_id Integer

 

Challenges 테이블:

  • challenge_id : 챌린지의 id
  • hacker_id : 해커의 id

Julia는 학생들에게 코딩 챌린지를 만들도록 요청했습니다. 각 학생이 만든 챌린지의 총 개수를 출력하는 쿼리를 작성하세요. 결과는 챌린지의 총 개수를 기준으로 내림차순으로 정렬합니다. 만약 여러 학생이 동일한 수의 챌린지를 만들었다면, hacker_id를 기준으로 정렬합니다. 여러 학생이 동일한 수의 챌린지를 만들었고 그 수가 생성된 챌린지의 최대 개수보다 적다면, 해당 학생들을 결과에서 제외합니다.

 

select
    hacker_id,
    count(challenge_id)
from  Challenges c
group by hacker_id

 

먼저 해커별로 만든 챌린지의 수를 구해준다.

 

select
    count_chall,
    count(count_chall)
from
(select
    hacker_id,
    count(challenge_id) count_chall
from  Challenges c
group by hacker_id) a
group by count_chall

 

해당 쿼리를 기반으로 해서 챌린지를 만든 수가 같은 사람들의 수를 센다.

 

select *
from
(select
    hacker_id,
    count(challenge_id) count_chall
from  Challenges c
group by hacker_id) a
left join
(select
    count_chall,
    count(count_chall)
from
(select
    hacker_id,
    count(challenge_id) count_chall
from  Challenges c
group by hacker_id) a
group by count_chall) cc on a.count_chall = cc.count_chall

 

위의 쿼리와 작성한 챌린지의 수를 센 쿼리를 결합해서 동점자가 몇명 있는지 센다.

 

select
    max(count_chall)
from
(select
    hacker_id,
    count(challenge_id) count_chall
from  Challenges c
group by hacker_id) a

 

작성한 챌린지의 최대값을 반환하는 새로운 쿼리를 작성한다.

 

select *
from
(
select
    hacker_id,
    count(challenge_id) count_chall
from  Challenges c
group by hacker_id
) a
left join
(
select
    count_chall,
    count(count_chall) ccc
from
(
select
    hacker_id,
    count(challenge_id) count_chall
from  Challenges c
group by hacker_id
) a
group by count_chall
) cc on a.count_chall = cc.count_chall
where cc.ccc = 1 or
cc.count_chall = (
select
    max(count_chall)
from
    (
        select
            hacker_id,
            count(challenge_id) as count_chall
        from Challenges c
        group by hacker_id
    ) as max_chall
)

 

위의 동점자가 몇명인지 세는 쿼리에 where절을 추가해서 동점자가 없는 행만 출력하거나 (cc쿼리의 ccc열이 1인 행) 작성한 챌린지의 수가 최대인 행들만 출력한다. 이때 최대값은 조금 전에 작성한 최대값 쿼리를 조건으로 사용한다.

 

select
    h.hacker_id,
    h.name,
    mc.count_chall
from Hackers h
inner join
(
select
    a.hacker_id,
    a.count_chall
from
    (
    select
        hacker_id,
        count(challenge_id) count_chall
    from  Challenges c
    group by hacker_id
    ) a
left join
    (
        select
            count_chall,
            count(count_chall) ccc
        from
            (
            select
                hacker_id,
                count(challenge_id) count_chall
            from  Challenges c
            group by hacker_id
            ) a
        group by count_chall
    ) cc on a.count_chall = cc.count_chall
where cc.ccc = 1 or
cc.count_chall = (
select
    max(count_chall)
from
    (
        select
            hacker_id,
            count(challenge_id) as count_chall
        from Challenges c
        group by hacker_id
    ) as max_chall
)
) mc on h.hacker_id = mc.hacker_id
order by mc.count_chall desc,  h.hacker_id

 

마지막으로 이름을 출력하기 위해서 Hackers테이블과 결합하고 조건에 맞게 정렬하면 완료!

 

sql 코드는 길어지니까 흐름을 읽기 너무 힘든것같다... 코드를 줄여서 작성할 수 있었을까? 아니면 코드 작성을 더 깔끔하게 해서 가독성을 높여야할까?