https://www.hackerrank.com/challenges/challenges/problem?isFullScreen=true
강의를 듣기 전 내 풀이
1. 아이디별로 만든 챌린지 수를 확인할 수 있는 테이블을 만들어줌
SELECT hacker_id,
COUNT(challenge_id) AS challenges_created
FROM Challenges
GROUP BY hacker_id
이 테이블을 이용해서 추후 조건에 사용될 challenges_created의 MAX 값을 구해주는 서브쿼리를 또 작성해야 했기에, WITH문을 사용해서 쿼리 맨 위로 빼버림
WITH sub AS (
SELECT hacker_id,
COUNT(challenge_id) AS challenges_created
FROM Challenges
GROUP BY hacker_id
)
그리고 MAX 값을 구하는 쿼리도 작성해줌 (추후 사용할 예정)
SELECT MAX(challenges_created) FROM sub
2. 1번의 테이블을 이용해서, 만든 챌린지 수별 학생 수를 구해줌
SELECT challenges_created,
COUNT(hacker_id) AS cnt
FROM sub
GROUP BY challenges_created
문제에서 cnt가 2 이상이고, challenges_created가 MAX 값보다 작은 challenges_created 값에 대해서는 제외해주길 원함
3. 2번 테이블을 이용해서, 결과에서 제외해야 할 챌린지 수를 구해줌
SELECT challenges_created,
COUNT(hacker_id) AS cnt
FROM sub
GROUP BY challenges_created
HAVING cnt >= 2
AND (SELECT MAX(challenges_created) FROM sub) > challenges_created
이때 challenges_created 값만 필요하기 때문에 cnt는 제거한 상태로 사용
SELECT challenges_created
FROM sub
GROUP BY challenges_created
HAVING COUNT(hacker_id) >= 2
AND (SELECT MAX(challenges_created) FROM sub) > challenges_created
4. 1번에서 만든 테이블에서 3번에 해당되는 challenges_created 값을 가진 행을 제거해줌
SELECT *
FROM sub
WHERE challenges_created NOT IN (3번쿼리)
5. 문제에서 학생들의 이름을 출력해주길 원하기 때문에 INNER JOIN을 이용해줌
SELECT s.hacker_id,
h.name,
s.challenges_created
FROM sub s
INNER JOIN hackers h ON s.hacker_id = h.hacker_id
WHERE challenges_created NOT IN (3번쿼리)
6. 문제에서 원하는 정렬 조건을 ORDER BY로 작성해줌
SELECT s.hacker_id,
h.name,
s.challenges_created
FROM sub s
INNER JOIN hackers h ON s.hacker_id = h.hacker_id
WHERE challenges_created NOT IN (3번쿼리)
ORDER BY challenges_created DESC, hacker_id
최종적으로는 다음과 같은 쿼리를 작성했다.
WITH sub AS (
SELECT c.hacker_id,
COUNT(challenge_id) AS challenges_created
FROM Challenges c
GROUP BY c.hacker_id
)
SELECT s.hacker_id,
h.name,
s.challenges_created
FROM sub s
INNER JOIN hackers h ON s.hacker_id = h.hacker_id
WHERE challenges_created NOT IN (
SELECT challenges_created
FROM sub
GROUP BY challenges_created
HAVING COUNT(hacker_id) >= 2
AND (SELECT MAX(challenges_created) FROM sub) > challenges_created
)
ORDER BY challenges_created DESC, hacker_id
강의를 듣고 정리한 풀이
우선 기본 골자 (문제에서 출력하기를 원하는 형태) 를 잡아준다.
SELECT c.hacker_id,
h.name,
COUNT(challenge_id) AS challenges_created
FROM challenges c
INNER JOIN hackers h ON c.hacker_id = h.hacker_id
GROUP BY c.hacker_id, h.name
HAVING -- 1) challenges_created가 MAX값인 경우
OR -- 2) challenges_created가 중복이 아닌 경우
ORDER BY challenges_created DESC, c.hacker_id
GROUP BY를 통해 연산된 challenges_created에 따라 조건이 다르게 걸리는 문제이므로 HAVING을 사용해줘야 한다.
challenges_created가 MAX값인 경우 동일한 갯수를 만든 사람이 몇명인지와 무관하게 출력
MAX가 아닌 경우 동일한 갯수를 만든 사람이 있다면 그만큼 만든사람 모두 출력 X
1) challenges_created가 MAX인 경우
SELECT MAX(challenges_created)
FROM (
SELECT c.hacker_id,
h.name,
COUNT(challenge_id) AS challenges_created
FROM challenges c
INNER JOIN hackers h ON c.hacker_id = h.hacker_id
)
이걸 HAVING절 조건에 쓰면 다음과 같다.
HAVING challenges_created = ( 1)번쿼리 내용 )
2) challenges_created가 중복이 아닌 경우
SELECT challenges_created,
COUNT(c.hacker_id) AS cnt
FROM (
SELECT c.hacker_id,
h.name,
COUNT(challenge_id) AS challenges_created
FROM challenges c
INNER JOIN hackers h ON c.hacker_id = h.hacker_id
)
GROUP BY challenges_created
HAVING cnt = 1
이걸 HAVING절 조건으로 쓰기 위해서는 SELECT 절에 challenges_created만 남아야 한다.
SELECT challenges_created
FROM (
SELECT c.hacker_id,
h.name,
COUNT(challenge_id) AS challenges_created
FROM challenges c
INNER JOIN hackers h ON c.hacker_id = h.hacker_id
)
GROUP BY challenges_created
HAVING COUNT(c.hacker_id) = 1 -- cnt를 HAVING절 조건으로 빼줌
HAVING challenges_created IN ( 2)번쿼리 내용 )
이때 challenges_created를 세어주기 위한 쿼리가 계속 반복적으로 사용되고 있음을 알 수 있다.
같은 동작을 계속 실행하는걸 막기 위해 WITH문을 사용해준다.
WITH sub AS (
SELECT c.hacker_id,
h.name,
COUNT(challenge_id) AS challenges_created
FROM challenges c
INNER JOIN hackers h ON c.hacker_id = h.hacker_id
GROUP BY c.hacker_id, h.name
)
정리하면 다음과 같다.
WITH sub AS (
SELECT c.hacker_id,
h.name,
COUNT(challenge_id) AS challenges_created
FROM challenges c
INNER JOIN hackers h ON c.hacker_id = h.hacker_id
GROUP BY c.hacker_id, h.name
)
SELECT hacker_id,
name,
challenges_created
FROM sub
WHERE challenges_created = (
SELECT MAX(challenges_created)
FROM sub)
OR challenges_created IN (
SELECT challenges_created
FROM sub
GROUP BY challenges_created
HAVING COUNT(hacker_id) = 1)
ORDER BY challenges_created DESC, hacker_id
배운점
1. 큰그림을 먼저 파악하기 위해 전체적인 골자에 대한 쿼리를 먼저 작성
2. GROUP BY할 때 SELECT에 연산자를 적지 않고, HAVING절에 연산자를 적어도 됨
3. 조건을 말로 정리한 후 그걸 구현하기 위한 코드를 작성하기
'SQL > 문제풀이' 카테고리의 다른 글
[HackerRank] Interviews (0) | 2024.05.09 |
---|---|
[HackerRank] The Report (0) | 2024.05.09 |
[HackerRank] Top Earners / N가지 풀이 (0) | 2024.05.08 |
[Leetcode] Department top three salaries (0) | 2024.05.08 |
[Leetcode] Department highest salary / N가지 풀이 (Subquery, Window Function) (0) | 2024.05.08 |