Contents
see ListOracle 계층구조 쿼리 - 답글/댓글 리스트
Oracle의 계층구조 쿼리는 CONNECT BY 절을 사용하여 트리 형태의 데이터를 조회합니다. 게시판 답글, 조직도, 카테고리 구조 등에 활용됩니다.
언제 사용하나요?
- 게시판 답글/댓글 목록 (들여쓰기)
- 조직도 (상위-하위 관계)
- 카테고리/메뉴 계층
- BOM(Bill of Materials) 구조
기본 테이블 구조
CREATE TABLE board (
board_seq NUMBER PRIMARY KEY,
parent_seq NUMBER, -- 부모 글 번호 (NULL이면 원글)
title VARCHAR2(200),
content CLOB,
writer VARCHAR2(50),
reg_date DATE DEFAULT SYSDATE,
grp_seq NUMBER, -- 같은 그룹 번호
depth NUMBER DEFAULT 0, -- 들여쓰기 레벨
sort_seq NUMBER -- 정렬 순서
);계층 쿼리 기본
-- 기본 계층 조회
SELECT
LEVEL,
LPAD(" ", (LEVEL-1)*2) || title AS title,
board_seq,
parent_seq
FROM board
START WITH parent_seq IS NULL -- 루트 조건
CONNECT BY PRIOR board_seq = parent_seq -- 연결 조건
ORDER SIBLINGS BY reg_date DESC; -- 같은 레벨 내 정렬
-- LEVEL: 계층 깊이 (루트=1)
-- PRIOR: 이전 행 참조
-- ORDER SIBLINGS BY: 형제 노드 간 정렬게시판 답글 목록 조회
SELECT
board_seq,
LPAD(" ", (LEVEL-1)*4) || title AS title,
writer,
TO_CHAR(reg_date, "YYYY-MM-DD HH24:MI") AS reg_date,
LEVEL AS depth
FROM board
WHERE use_yn = "Y"
START WITH parent_seq IS NULL
CONNECT BY PRIOR board_seq = parent_seq
ORDER SIBLINGS BY grp_seq DESC, sort_seq ASC;
/* 결과 예시
board_seq title writer depth
1 첫 번째 글 홍길동 1
2 ㄴ 답글1 김철수 2
5 ㄴ 답글1-1 이영희 3
3 ㄴ 답글2 박민수 2
4 두 번째 글 최유진 1
*/계층 함수들
-- SYS_CONNECT_BY_PATH: 경로 표시
SELECT
board_seq,
SYS_CONNECT_BY_PATH(title, " > ") AS path
FROM board
START WITH parent_seq IS NULL
CONNECT BY PRIOR board_seq = parent_seq;
-- 결과: " > 원글 > 답글1 > 답글1-1"
-- CONNECT_BY_ROOT: 루트 값 조회
SELECT
board_seq,
title,
CONNECT_BY_ROOT title AS root_title,
CONNECT_BY_ROOT board_seq AS root_seq
FROM board
START WITH parent_seq IS NULL
CONNECT BY PRIOR board_seq = parent_seq;
-- CONNECT_BY_ISLEAF: 리프 노드 확인
SELECT
board_seq,
title,
CONNECT_BY_ISLEAF AS is_leaf -- 1: 리프, 0: 부모
FROM board
START WITH parent_seq IS NULL
CONNECT BY PRIOR board_seq = parent_seq;그룹 번호 관리 방식
-- 원글 등록
INSERT INTO board (board_seq, grp_seq, depth, sort_seq, ...)
VALUES (seq.NEXTVAL, seq.CURRVAL, 0, 0, ...);
-- 답글 등록 (그룹 번호 유지, 정렬 순서 조정)
DECLARE
v_grp_seq NUMBER;
v_sort_seq NUMBER;
BEGIN
-- 부모글의 그룹번호와 정렬순서 조회
SELECT grp_seq, sort_seq
INTO v_grp_seq, v_sort_seq
FROM board WHERE board_seq = :parent_seq;
-- 같은 그룹에서 정렬순서 밀기
UPDATE board
SET sort_seq = sort_seq + 1
WHERE grp_seq = v_grp_seq
AND sort_seq > v_sort_seq;
-- 답글 등록
INSERT INTO board (
board_seq, parent_seq, grp_seq,
depth, sort_seq, ...
) VALUES (
seq.NEXTVAL, :parent_seq, v_grp_seq,
(SELECT depth + 1 FROM board WHERE board_seq = :parent_seq),
v_sort_seq + 1, ...
);
END;조직도 조회
SELECT
emp_id,
LPAD(" ", (LEVEL-1)*2) || emp_name AS emp_name,
position,
dept_name,
LEVEL
FROM employees
START WITH manager_id IS NULL
CONNECT BY PRIOR emp_id = manager_id
ORDER SIBLINGS BY position_order;순환 참조 방지
-- NOCYCLE: 순환 참조 무시
SELECT
board_seq,
title,
CONNECT_BY_ISCYCLE AS is_cycle
FROM board
START WITH parent_seq IS NULL
CONNECT BY NOCYCLE PRIOR board_seq = parent_seq;계층 쿼리 활용 예시
-- 특정 글의 모든 하위 글 조회
SELECT * FROM board
START WITH board_seq = :target_seq
CONNECT BY PRIOR board_seq = parent_seq;
-- 특정 글의 모든 상위 글 조회 (역방향)
SELECT * FROM board
START WITH board_seq = :target_seq
CONNECT BY PRIOR parent_seq = board_seq;
-- 특정 레벨까지만 조회
SELECT * FROM board
WHERE LEVEL <= 3
START WITH parent_seq IS NULL
CONNECT BY PRIOR board_seq = parent_seq;주의사항
- 대용량 데이터에서 성능 저하 가능
- 인덱스 생성: parent_seq, grp_seq
- 순환 참조 방지 로직 필수