데이터 분석/SQL
SQL) 재귀 쿼리로 반복문 만들기 / WITH RECURSIVE
engwoon
2024. 12. 26. 20:29
≣ 목차
재귀 쿼리
- 반복적으로 데이터를 생성하는 작업이 필요할 때 사용된다.
- 파이썬의 for문과 비슷한 역할 수행
기본 구조
WITH RECURSIVE cte_name AS (
-- 1. Anchor 부분: 초기 데이터 생성
SELECT <columns>
FROM <table>
WHERE <condition>
UNION ALL
-- 2. Recursive 부분: 재귀적으로 처리할 쿼리
SELECT <columns>
FROM cte_name -- 자기 자신을 참조
WHERE <condition>
)
SELECT * FROM cte_name;
1. Anchor 부분
- 재귀 쿼리의 시작점. 초기 데이터를 생성한다.
2. Recursive 부분
- Anchor에서 생성된 데이터를 기반으로 반복적으로 계산을 수행한다.
- 여기서 `cte_name`을 참조하여 자기 자신을 호출
3. 종료 조건
- `where`절로 반복을 멈출 조건을 지정한다.
4. 최종 select
- 재귀적으로 생성된 데이터를 최종적으로 출력한다.
활용 예시 1. 숫자 생성
- 숫자 생성 (0~N까지)
WITH RECURSIVE numbers AS (
-- Anchor: 0부터 시작
SELECT 0 AS num
UNION ALL
-- Recursive: num에 1씩 추가
SELECT num + 1
FROM numbers
WHERE num < 10 -- 종료 조건 (num이 10보다 작을 때까지만 반복)
)
SELECT num
FROM numbers;
출력 결과
활용 예시 2. 시간을 24시간으로 표현한 테이블 생성
WITH RECURSIVE time AS (
SELECT 0 AS hour
UNION ALL
SELECT hour + 1
FROM time
WHERE hour < 23
)
- SELECT 0 AS hour
- 초기 값으로 hour = 0을 생성한다. (재귀의 시작점)
- UNION ALL
- hour에 1을 더한 값을 계속 추가한다.
- 예: 0 → 1 → 2 → ... → 23
- WHERE hour < 23
- hour가 23이 되면 멈추도록 설정한다.
출력 결과
예제) 입양 시각 구하기
코드카타 73번
문제:
0시부터 23시까지, 각 시간대별로 입양이 몇 건이나 발생했는지 조회하는 SQL문을 작성해주세요.
이때 결과는 시간대 순으로 정렬해야 합니다.
WITH RECURSIVE time AS (
SELECT 0 AS hour
UNION ALL
SELECT hour + 1
FROM time
WHERE hour < 23
)
SELECT t.hour,
COUNT(animal_id) as count
FROM time t
LEFT JOIN (
SELECT *, HOUR(datetime) AS hour
FROM animal_outs
) a
ON t.hour = a.hour
GROUP BY 1
ORDER BY 1;
- `WITH RECURSIVE`
- `time`테이블에서 0~23시까지 `hour` 값을 생성.
- `LEFT JOIN`
- `time.hour`와 `animal_outs`에서 `HOUR(datetime)`으로 추출한 `hour` 값을 결합.
- 😱이때 실수한 것😱
-
더보기- select date_format(datetime, '%H') as HOUR from animal_outs 으로 했더니 오류 남.
🔎 왜?
- `HOUR(datetime)` : 정수(int)값을 반환함. 0,1,2 ...
- `DATE_FORMAT(datetime, %H)`: 문자열(varchar)값을 반환함. 00,01,02 ...
👉 결론
`JOIN`에서 데이터 형식이 맞지 않아서 매칭이 안 된거임.
-
- `COUNT`
- 각 시간에 해당하는 데이터 개수를 계산
출력 결과