[프로그래머스][MySQL] Lv. 4 입양 시각 구하기(2)
문제 설명
https://school.programmers.co.kr/learn/courses/30/lessons/59413
단순히 GROUP BY를 해서는 풀지 못하는 문제이다.
GROUP BY를 하면 일부의 시간만 출력되고 모든 시간이 출력되지는 않기 때문이다.
즉, 문제에서는 0시부터 23시까지 값이 없는 데이터도 출력하라 하였는데,
데이터가 없는 시간이 존재한다!
파이썬으로 하면 쉽게 할 수 있을 것 같은데, 좀 어려웠다ㅠㅠ
그래서 다른 사람의 풀이를 보고 풀어보았다.
풀이
-- RECURSIVE CTE
WITH RECURSIVE CTE AS(
SELECT 0 AS NUM
UNION ALL
SELECT NUM +1
FROM CTE
WHERE NUM < 23
)
SELECT CTE.NUM HOUR, COUNT(HOUR(O.DATETIME)) AS COUNT
-- COUNT(*)으로 하면 데이터 없는 ROW도 1로 CNT 하므로 COUNT(HOUR(O.DATETIME)) 사용
FROM ANIMAL_OUTS O RIGHT OUTER JOIN CTE
ON HOUR(O.DATETIME) = CTE.NUM
GROUP BY CTE.NUM
ORDER BY CTE.NUM
위는 Recursive CTE (재귀 CTE)를 사용한 풀이이다.
재귀 CTE는 일반적인 CTE와 달리, 재귀적으로 데이터를 생성해가는 CTE이다.
이와 관련된 내용은 별도의 글로 따로 작성해두었다!
https://yeonnys.tistory.com/entry/MySQL-Recursive-CTE
즉, Recursive CTE를 활용해 0부터 23까지 숫자를 나타내는 별도의 테이블을 생성하고,
이를 본래 테이블과 JOIN하여 입양 건 수를 세는 것이다.
앞서 말한 Recursive CTE를 실행하면, 위와 같은 결과가 나오게 된다.
이를 HOUR(DATETIME)과 JOIN하며, 이 때 JOIN 조건은 CTE 테이블의 모든 값이 들어갈 수 있도록 한다.
다른 풀이
SET을 사용한 풀이도 볼 수 있었다.
SET은 어떤 변수에 특정 값을 할당할 때 쓰는 명령어이다.
SET @HOUR = -1;
SELECT (@HOUR := @HOUR +1) AS HOUR
FROM ANIMAL_OUTS
WHERE @HOUR < 23;
즉, 위와 같은 쿼리는 @HOUR 변수에 -1을 할당한 후 22까지 +1씩 더해준다는 의미이다.
최종적으로 이를 이용해 입양 건 수를 다음과 같이 셀 수 있다.
SET @HOUR = -1;
SELECT (@HOUR := @HOUR +1) AS HOUR,
(SELECT COUNT(HOUR(DATETIME))
FROM ANIMAL_OUTS
WHERE HOUR(DATETIME)=@HOUR) AS COUNT
FROM ANIMAL_OUTS
WHERE @HOUR < 23;
이 때 주의할 점은,
SET 이외의 명령문에서는 "="이 비교연산자로 취급되기 때문에
SELECT 문에서 이를 활용할 때는 ":="을 사용해야 한다는 것이다.
느낀점
생각보다 어려운 문제여서 처음 아는 것이 많았던 문제였다.
잘 기억해두고, 다음에 다시 풀어봐야겠다.