SQL WITH 절: 공통 테이블 식(CTE)과 재귀 쿼리
Published: 2026-02-04
WITH 절(공통 테이블 식, CTE라고도 함)은 쿼리 안에서 참조할 수 있는 임시 이름 결과 집합을 정의할 수 있게 해 줍니다. 이를 통해 복잡한 쿼리를 더 읽기 쉽고 재사용 가능하게 만들 수 있습니다. SQLite, PostgreSQL, MySQL 8.0+, SQL Server, Oracle 등 대부분의 최신 SQL 데이터베이스에서 사용할 수 있습니다.
샘플 데이터
모든 예제에서 다음 두 개의 테이블을 사용합니다:
employees 테이블:
| id | name | manager_id | salary |
|---|---|---|---|
| 1 | Alice | NULL | 120000 |
| 2 | Bob | 1 | 80000 |
| 3 | Carol | 1 | 85000 |
| 4 | Dave | 2 | 60000 |
| 5 | Eve | 2 | 62000 |
| 6 | Frank | 3 | 58000 |
sales 테이블:
| id | employee_id | amount | month |
|---|---|---|---|
| 1 | 2 | 5000 | January |
| 2 | 2 | 6000 | February |
| 3 | 3 | 7000 | January |
| 4 | 3 | 8000 | February |
| 5 | 4 | 3000 | January |
| 6 | 5 | 4000 | January |
| 7 | 6 | 2500 | February |
기본 WITH 절(비재귀)
WITH 절은 쿼리가 실행되는 동안에만 존재하는 하나 이상의 이름 있는 임시 테이블을 정의합니다.
예제: 직원별 총 매출
employee_sales CTE는 직원별 총 매출을 계산하고, 이를 employees 테이블과 조인하여 이름을 표시합니다.
여러 개의 CTE
여러 개의 CTE를 콤마로 구분해 정의할 수 있습니다. 뒤에 나오는 CTE는 앞에서 정의한 CTE를 참조할 수 있습니다.
예제: 여러 지표를 활용한 매출 분석
WITH RECURSIVE: 계층 구조 탐색
WITH RECURSIVE를 사용하면 CTE가 자기 자신을 참조할 수 있어, 계층형 또는 트리 형태의 데이터를 탐색할 수 있습니다. 조직도, 카테고리 계층, 기타 부모-자식 관계를 다룰 때 유용합니다.
재귀 CTE는 두 부분으로 구성됩니다:
- 기본 쿼리(Base query): 초기 행 집합
- 재귀 쿼리(Recursive query): 관련 행을 찾기 위해 CTE 자신을 참조하는 쿼리
예제: 조직도(특정 관리자의 모든 직원 찾기)
Alice(CEO) 아래에 있는 모든 직원을 찾습니다:
예제: 보고 체계(관리자 계층 찾기)
Dave(→ Bob → Alice로 보고하는 직원)의 전체 보고 체계를 찾습니다:
데이터베이스별 WITH RECURSIVE 문법
WITH RECURSIVE는 다음에서 지원됩니다:
- SQLite — 3.8.3+ (2013)
- PostgreSQL — 8.4+ (2009)
- SQL Server — 2005+ (이름: “Recursive CTE”)
- Oracle — 11g+ (이름: “Recursive Subquery Factoring”)
- MySQL — 8.0+ (2018)
참고: 구버전 MySQL 및 일부 다른 데이터베이스는 재귀 CTE를 지원하지 않습니다. 이 경우 저장 프로시저나 애플리케이션 레벨 재귀 같은 다른 접근 방식이 필요할 수 있습니다.
WITH 절의 일반적인 활용 사례
- 복잡한 쿼리 단순화 — 큰 쿼리를 논리적인 단계로 나누기
- 서브쿼리 재사용 — 계산을 한 번 정의하고 여러 번 사용하기
- 계층 구조 탐색 — 조직도, 카테고리, 댓글 트리 등 탐색
- 수열 생성 — 숫자 범위나 날짜 범위 생성
- 점진적 집계 — 여러 단계를 거쳐 결과를 누적해서 만들기
요약
WITH(CTE)는 쿼리에서 사용할 이름 있는 임시 결과 집합을 생성합니다.- 여러 개의 CTE를 연쇄적으로 정의해 사용할 수 있습니다.
WITH RECURSIVE를 사용하면 계층형 쿼리를 위해 CTE가 자기 자신을 참조할 수 있습니다.- 재귀 CTE는
UNION ALL로 구분되는 기본 부분과 재귀 부분이 필요합니다. - 모든 최신 SQL 데이터베이스에서 지원되지만, 세부 문법은 약간씩 다를 수 있습니다.
위 예제들을 수정해 보면서 다양한 계층 구조나 계산을 직접 탐색해 보세요!