프로그래머스 SQL 문제를 풀다가 재귀적 표현을 봤다.
로직 짤 때도 알고 있지만 쉽게 쓰지 않던 부분인데... SQL에도 있다니;;;
WITH로 쿼리에서 따로 활용할 테이블? 뷰?를 설정해주게 되는데
여기에서 RECURESIVE를 써주면 자기 자신을 반복 호출하여 계층형 데이터를 조회할 수 있다.
보통 트리 구조의 데이터를 다룰 때 유용하다.
-- 기본 문법
WITH RECURSIVE [이름] AS (
기본 쿼리 (재귀가 시작할 점)
UNION ALL
재귀 쿼리 (자기 자신 활용)
)
SELECT * FROM [이름];
위의 형식으로 사용하게 된다.
WITH RECURSIVE TIME AS(
SELECT 0 AS HOUR
UNION ALL
SELECT HOUR + 1
FROM TIME
WHERE HOUR < 23
)
SELECT * FROM TIME;
이렇게 사용하면 0~23 까지는 숫자가 출력된다.
| id | name | manager_id |
|---|---|---|
| 1 | Kim | NULL |
| 2 | Bob | 1 |
| 3 | Amy | 1 |
| 4 | Dave | 2 |
| 5 | Eve | 2 |
WITH RECURSIVE employee_hierarchy AS (
SELECT id, name, manager_id, 1 AS level
FROM employees
WHERE id = 2
UNION ALL
SELECT e.id, e.name, e.manager_id, eh.level + 1
FROM employees e
JOIN employee_hierarchy eh ON e.manager_id = eh.id
)
SELECT * FROM employee_hierarchy;
=> 출력결과
| id | name | manager_id | level |
|---|---|---|---|
| 2 | Bob | 1 | 1 |
| 4 | Dave | 2 | 2 |
| 5 | Eve | 2 | 2 |
주어진 테이블에서 직원과 각자의 maneger가 매칭된 데이터가 있다고 하자.
여기서 Bob의 부하 직원들 내역을 뽑고 싶다.
따라서 Bob에게는 level1을 부여하고 Bob을 manager로 둔 직원들을 뽑아 level2로 계층까지 출력을 해주었다.
만약 테이블이 아래와 같이 바뀌어서 Bob의 바로 아래 부하직원에게도 부하직원이 있다면??
| id | name | manager_id |
|---|---|---|
| 1 | Kim | NULL |
| 2 | Bob | 1 |
| 3 | Amy | 1 |
| 4 | Dave | 2 |
| 5 | Eve | 2 |
| 6 | Frank | 3 |
| 7 | Alice | 4 |
| 8 | Charlie | 4 |
부하직원의 부하직원까지 같은 라인?에 해당하는 직원들이 아래와 같이 출력될 것이다.
| id | name | manager_id | level |
|---|---|---|---|
| 2 | Bob | 1 | 1 |
| 4 | Dave | 2 | 2 |
| 5 | Eve | 2 | 2 |
| 7 | Alice | 4 | 3 |
| 8 | Charlie | 4 | 3 |
🚨무한 루프 방지!!
위의 경우는 데이터 제한이 있어 종료되지만...
만약 상수를 끊임없이 뽑아내는 경우 무한루프를 돌게 된다.
WITH RECURSIVE TIME AS(
SELECT 0 AS HOUR
UNION ALL
SELECT HOUR + 1
FROM TIME
WHERE HOUR < 23
)
SELECT * FROM TIME;
제일 처음 주어진 쿼리에서 처럼 HOUR<23의 조건을 주거나
직원 계층을 뽑는 경우라면 LEVEL로 제한을 두어 해당 부분까지만 진행되도록 하는 것이 좋다!!