✅ 문제
보호소에서는 몇 시에 입양이 가장 활발하게 일어나는지 알아보려 합니다. 0시부터 23시까지, 각 시간대별로 입양이 몇 건이나 발생했는지 조회하는 SQL문을 작성해주세요. 이때 결과는 시간대 순으로 정렬해야 합니다.
처음에 문제를 보고 리쿼시브 쿼리( 재귀쿼리 )를 생각하지 못했다.
문제 결과가 아래와 같이 0시부터 23시까지 모두 출력이되어야됐다.
HOUR COUNT
0 0
1 0
2 0
3 0
나는 재귀쿼리하면 메뉴만들때밖에 생각하지못했는데 아직 익숙하지않은거 같다.
✅ 재귀 쿼리란?
- 반복적으로 작동될 쿼리
- 즉, 어떤 쿼리를 반복적으로 실행
- 자료들의 계층을 파악하는데 용이
✅ 재귀 쿼리 작성 방법
- 임시 테이블을 불러올 때 사용하던 WITH와 함께 작성
- 테이블들을 합쳐주는 UNION을 사용
WITH RECURSIVE TEMP_NAME (Col1, Col2, …) AS(
Non_RECURSIVE QUREY
UNION ALL
RECURSIVE QUREY
)
SELECT COL1, COL2
FROM TEMP_NAME
✅ 재귀쿼리 예시 1
조직도를 예시로 보자면

CREATE TABLE division
(
division_code character varying(20) NOT NULL PRIMARY KEY,
division_name character varying(20) NOT NULL,
upper_division_code character varying(20) NOT NULL
);
INSERT INTO division VALUES ('develop_division', '개발본부', '');
INSERT INTO division VALUES ('front_team', '프론트팀', 'develop_division');
INSERT INTO division VALUES ('infra_team', '인프라팀', 'develop_division');
INSERT INTO division VALUES ('back_team', '백엔드팀', 'develop_division');
INSERT INTO division VALUES ('web_part', '웹파트', 'front_team');
INSERT INTO division VALUES ('aos_part', 'AOS파트', 'front_team');
INSERT INTO division VALUES ('ios_part', 'IOS파트', 'front_team');
INSERT INTO division VALUES ('1_part', '1파트', 'back_team');
INSERT INTO division VALUES ('2_part', '2파트', 'back_team');
📚 재귀쿼리 (모든 하위 부서 찾기)
첫번째 케이스는 기준 부서의 조직도 아래 모든 부서를 찾아본다
WITH RECURSIVE find_division(division_code, division_name, upper_division_code, DEPTH)
as (
--START_QUERY
select division_code, division_name, upper_division_code, 1
from division
where 1=1
and division_code = 'develop_division'
union
--REPEAT_QUERY
select d.division_code, d.division_name, d.upper_division_code, fd.DEPTH+1
from find_division fd
INNER JOIN division d on d.upper_division_code = fd.division_code --case1. 조직도 아래의 모든 부서 찾기
)
--VIEW_QUERY
select * from find_division;
쿼리 실행에 관하여 순서대로 설명해보면,
- --START_QUERY 영역에 해당 부분을 실행하여 '개발본부'의 데이터를 일단 가져온다.
- 기준이 되는 데이터를 find_division 이라는 임시뷰에 저장한다.
- --REPEAT_QUERY 영역에 해당 부분을 실행하여,
이미 들어있는 임시뷰와 또 다시 조직도 테이블을 조인하여
'개발본부'의 코드인 'develop_division'을 상위부서로 갖는 부서들을 찾는다.
=> 데이터상 프론트팀, 인프라팀, 백엔드팀이 나온다. - 해당 데이터도 find_division 이라는 임시뷰에 저장한다.
- 추가된 데이터를 대상으로 본인코드들을 상위부서로 갖는 부서들을 찾는다.
- 지속 반복하여 모든 하위 부서를 찾는다.
📚 재귀쿼리 (모든 상위 부서 찾기)
내 기준 상위 부서를 찾고 싶을수도 있다. 예를 들어, '웹파트'의 상위 부서를 찾는다고 하면, case1 해당하는 줄을 주석하고 case2에 해당하는 부분의 주석을 풀면 쉽게 '웹파트 => 프론트팀 => 개발본부' 라는 결과를 얻을 수 있다.
WITH RECURSIVE find_division(division_code, division_name, upper_division_code, DEPTH)
as (
--START_QUERY
select division_code, division_name, upper_division_code, 1
from division
where 1=1
and division_code = 'web_part'
union
--REPEAT_QUERY
select d.division_code, d.division_name, d.upper_division_code, fd.DEPTH+1
from find_division fd
INNER JOIN division d on fd.upper_division_code = d.division_code
)
--VIEW_QUERY
select * from find_division;
📚 프로그래머스 문제
자 드디어 이제 프로그래머스 문제이다
WITH RECURSIVE A AS(
SELECT 0 AS HOUR
UNION ALL
SELECT HOUR + 1 AS HOUR
FROM A
WHERE HOUR < 23
)
SELECT A.HOUR, COUNT(ANIMAL_ID) AS COUNT
FROM A LEFT JOIN ANIMAL_OUTS B ON A.HOUR = HOUR(B.DATETIME)
GROUP BY HOUR
ORDER BY HOUR

다음과같이 나타낼수 있다.
✏️공부한 내용
Recursive쿼리에 대해서 알수있었고 초기값을 위에 쓰고 union으로아래에는 반복될 쿼리를 넣고 해당값으로 계층형을 나타낼수 있다.
아직 공부가 더필요하지만 무한루프를 고려해야되고 해당 방어코드도 넣어야될수도있다.
'Algorithm' 카테고리의 다른 글
| [SQL 알고리즘] SolveSql -복수 국적 메달 수상한 선수 찾기 (0) | 2025.05.15 |
|---|---|
| [SQL 알고리즘] 프로그래머스 -대장균의 크기에 따라 분류하기 2 (0) | 2024.12.04 |
| [SQL 알고리즘] 프로그래머스 - 식품분류별 가장 비싼 식품의 정보 조회하기 (2) | 2024.11.27 |
| [SQL 알고리즘] 프로그래머스 - 식품분류별 가장 비싼 식품의 정보 조회하기 (0) | 2024.11.27 |
| [SQL 알고리즘] 프로그래머스 - 저자 별 카테고리 별 매출액 집계하기 (2) | 2024.11.21 |