범주 트리 탐색하기
부모-자식 트리를 완전히 확장합니다.
범주 트리 탐색하기은(는) CoddyKit의 무료 SQL Academy 강의입니다. 이것은 4개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 SQL Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. SQL Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
범주 트리란 무엇인가
많은 실제 데이터세트에는 부모-자식 관계가 있습니다. 제품 카탈로그에는 전자 제품 → 휴대전화 → 스마트폰과 같은 범주가 있을 수 있습니다. 각 노드에 부모가 있어 트리 구조를 이룹니다.
에스큐엘에서는 일반적으로 자기 참조 테이블에 이를 저장합니다. 각 행에는 id가 있고, 동일한 테이블의 다른 행을 가리키는 parent_id가 있습니다.
CREATE TABLE categories (
id INT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
parent_id INT REFERENCES categories(id)
);범주 데이터 예시
작은 범주 트리를 채워 보겠습니다. 루트 노드에는 부모가 없으므로 parent_id = NULL입니다. 다른 모든 노드는 NULL이 아닌 parent_id로 자신의 부모를 가리킵니다.
INSERT INTO categories (id, name, parent_id) VALUES
(1, 'Electronics', NULL),
(2, 'Phones', 1),
(3, 'Laptops', 1),
(4, 'Smartphones', 2),
(5, 'Feature Phones', 2),
(6, 'Gaming Laptops', 3),
(7, 'Ultrabooks', 3);단순 질의의 문제
일반적인 SELECT는 한 번에 한 수준만 가져올 수 있습니다. 세 수준 깊이까지 도달하려면 서로 다른 질의 세 개 또는 자기 조인 세 개가 필요하며, 트리가 커질수록 관리할 수 없게 됩니다.
WITH RECURSIVE는 질의가 자신의 출력을 참조하도록 하여 이 문제를 해결합니다. 새로운 행이 더 이상 발견되지 않을 때까지 수준별로 탐색합니다.
-- This only shows direct children of Electronics (level 1)
SELECT id, name
FROM categories
WHERE parent_id = 1;WITH RECURSIVE의 구조
재귀 CTE에는 UNION ALL로 구분되는 두 부분이 있습니다:
1. 앵커 멤버 — 시작 행을 제공하는 일반 SELECT입니다.
2. 재귀 멤버 — CTE를 자기 자신과 조인하여 각 반복마다 다음 수준을 생성하는 SELECT입니다.
실행 엔진은 재귀 멤버가 행을 하나도 반환하지 않을 때까지 이를 반복합니다.
WITH RECURSIVE cte AS (
-- Anchor: starting rows
SELECT ...
UNION ALL
-- Recursive: join cte to base table
SELECT ... FROM base_table JOIN cte ON ...
)
SELECT * FROM cte;루트에서 전체 트리 순회하기
parent_id IS NULL인 루트에서 시작하여 모든 하위 노드까지 내려갑니다. 재귀 멤버는 누적된 각 행을 부모-자식 관계에 따라 categories에 다시 조인합니다.
WITH RECURSIVE category_tree AS (
-- Anchor: root nodes
SELECT id, name, parent_id, 1 AS depth
FROM categories
WHERE parent_id IS NULL
UNION ALL
-- Recursive: children of current level
SELECT c.id, c.name, c.parent_id, ct.depth + 1
FROM categories c
JOIN category_tree ct ON ct.id = c.parent_id
)
SELECT id, name, depth
FROM category_tree
ORDER BY depth, id;경로 추적하기
루트에서 각 노드까지의 전체 경로를 기록하면 유용합니다. 재귀가 더 깊어질 때 조상 이름을 연결하여 path 문자열을 만들 수 있습니다.
이렇게 하면 전자제품 / 휴대폰 / 스마트폰과 같은 탐색 경로를 쉽게 표시할 수 있습니다.
WITH RECURSIVE category_tree AS (
SELECT id, name, parent_id,
name AS path
FROM categories
WHERE parent_id IS NULL
UNION ALL
SELECT c.id, c.name, c.parent_id,
ct.path || ' / ' || c.name
FROM categories c
JOIN category_tree ct ON ct.id = c.parent_id
)
SELECT id, name, path
FROM category_tree
ORDER BY path;특정 노드에서 시작하기
루트에서 시작할 필요는 없습니다. 앵커의 WHERE 절을 변경하면 어떤 노드의 하위 트리든 순회할 수 있습니다. 여기서는 휴대폰(식별자 = 2)에서 시작하여 모든 하위 노드를 가져옵니다.
WITH RECURSIVE subtree AS (
SELECT id, name, parent_id, 0 AS depth
FROM categories
WHERE id = 2 -- start at Phones
UNION ALL
SELECT c.id, c.name, c.parent_id, s.depth + 1
FROM categories c
JOIN subtree s ON s.id = c.parent_id
)
SELECT id, name, depth
FROM subtree
ORDER BY depth, id;위쪽으로 순회하기: 모든 조상 찾기
트리를 반대 방향으로, 즉 리프에서 루트까지 위쪽으로 순회할 수도 있습니다. 조인 방향만 바꾸어 아래쪽이 아니라 parent_id를 따라 위쪽으로 이동하면 됩니다. 알려진 리프 노드의 전체 탐색 경로가 필요할 때 유용합니다.
WITH RECURSIVE ancestors AS (
SELECT id, name, parent_id
FROM categories
WHERE id = 4 -- start at Smartphones
UNION ALL
SELECT c.id, c.name, c.parent_id
FROM categories c
JOIN ancestors a ON a.parent_id = c.id
)
SELECT id, name
FROM ancestors
ORDER BY id;들여쓰기된 표시 추가하기
자식 노드에 시각적으로 들여쓰기를 적용하는 것은 일반적인 사용자 인터페이스 패턴입니다. depth 열과 함께 REPEAT(또는 LPAD)를 사용하여 각 이름 앞에 공백을 추가하면 텍스트 기반 트리 보기를 만들 수 있습니다.
WITH RECURSIVE category_tree AS (
SELECT id, name, parent_id, 0 AS depth
FROM categories
WHERE parent_id IS NULL
UNION ALL
SELECT c.id, c.name, c.parent_id, ct.depth + 1
FROM categories c
JOIN category_tree ct ON ct.id = c.parent_id
)
SELECT
REPEAT(' ', depth) || name AS indented_name,
depth
FROM category_tree
ORDER BY path;무한 반복 방지하기
데이터에 순환이 포함되어 있으면(A가 B의 부모이고 B가 A의 부모인 경우) 재귀가 영원히 실행되어 오류가 발생합니다. 방문한 ID를 배열에 기록하고 현재 ID가 이미 배열에 있으면 중지하여 이를 방지할 수 있습니다.
WITH RECURSIVE safe_tree AS (
SELECT id, name, parent_id,
ARRAY[id] AS visited
FROM categories
WHERE parent_id IS NULL
UNION ALL
SELECT c.id, c.name, c.parent_id,
st.visited || c.id
FROM categories c
JOIN safe_tree st ON st.id = c.parent_id
WHERE c.id <> ALL(st.visited) -- stop if already seen
)
SELECT id, name FROM safe_tree;노드별 하위 노드 수 세기
전체 트리를 확보하면 이를 집계할 수 있습니다. 여기서는 자식 행을 조상 목록에 대응시켜 그룹화하여 각 노드의 하위 노드 수를 셉니다. 탐색 메뉴에서 범주 이름 옆에 항목 수를 표시할 때 유용합니다.
WITH RECURSIVE category_tree AS (
SELECT id, name, parent_id, id AS root_id
FROM categories
WHERE parent_id IS NULL
UNION ALL
SELECT c.id, c.name, c.parent_id, ct.root_id
FROM categories c
JOIN category_tree ct ON ct.id = c.parent_id
)
SELECT
root_id,
COUNT(*) - 1 AS descendant_count
FROM category_tree
GROUP BY root_id
ORDER BY root_id;빠른 확인
재귀 범주 트리 쿼리에 대한 이해도를 확인해 보십시오.
학습 내용 정리
이 수업에서는 WITH RECURSIVE를 사용하여 자기 참조 범주 테이블을 순회하는 방법을 배웠습니다.
핵심 내용:
- 앵커 멤버는 시작 노드(일반적으로 루트)를 선택합니다.
- 재귀 멤버는 CTE를 기본 테이블에 다시 조인하여 다음 수준을 찾습니다.
- 각 노드가 몇 단계 깊이에 있는지 추적하려면 depth 열을 추가합니다.
- 탐색 경로를 생성하려면 path 문자열을 만듭니다.
- parent_id를 반대 방향으로 따라 위쪽으로 순회하면 모든 조상을 찾을 수 있습니다.
- 잘못된 데이터의 순환을 방지하려면 visited 배열을 사용합니다.
AI 튜터와 함께 SQL을(를) 배우세요 — 무료
브라우저에서 실제 코드를 작성하고 실행하며, 24/7 AI 튜터로부터 즉각적인 도움을 받고, 웹이나 앱에서 중단한 부분부터 계속 학습하세요.
- 코스
- 46
- 레슨
- 183
자주 묻는 질문
“범주 트리 탐색하기” 강의는 무료인가요?
네 — “범주 트리 탐색하기” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 SQL Academy 강의 전체를 잠금 해제할 수 있습니다. SQL Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“범주 트리 탐색하기”에서 뭘 배우나요?
부모-자식 트리를 완전히 확장합니다. 브라우저에서 직접 실행하는 실습 코드로 SQL Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
SQL Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 SQL Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 2번째 강의입니다.
“범주 트리 탐색하기” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 SQL Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 SQL Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.
이 강의의 모든 강의
- 재귀 CTE의 작동 원리
- 범주 트리 탐색하기
- 계열과 시퀀스 생성
- 무한 반복 피하기