DB
[MySQL] 계층 쿼리 (hierarchical query)
Initsave
2024. 5. 23. 12:34
계층 쿼리란 무엇일까? 주로 트리 구조 데이터를 쿼리하는데 사용되며, 재귀쿼리(자기 자신을 반복적으로 참조, 부모-자식 참조)의 일종으로 계층적 데이터를 처리하는 쿼리이다. (이전 포스팅에서도 같은 설명)
mysql 은 oracle과는 다르게 2가지 방식으로 계층쿼리를 구할 수 있다1. 재귀 쿼리 : 서브 쿼리를 이용해서 자기자신을 호출 (재귀)2. CTE(Commen Table Expressions) : Mysql 8.0 이상 지원하며 키워드가 존재한다.
WITH RECURSIVE: 재귀적인 공통 테이블 표현식(CTE)을 정의
UNION ALL: 초기 쿼리와 재귀 쿼리를 결합하기 위해 사용,
초기 쿼리는 시작점을 정의,
재귀 쿼리는 부모-자식 관계를 탐색하여 계층을 생성
SELECT: 내부의 초기 쿼리와 재귀 쿼리에서 필요한 필드를 선택, 결과 집합에 포함될 열을 지정
JOIN: 부모와 자식 테이블을 연결, 부모-자식 관계를 기반으로 재귀적으로 데이터를 검색가능
ORDER BY: 정렬 순서를 지정, 일반적으로는 계층 구조를 표시할 때 레벨 순서로 정렬
LEVEL: 현재 깊이 레벨을 나타내는 열,재귀 쿼리에서 레벨을 증가시키면서 계층을 구성하는 데 사용
WHERE: 초기 쿼리에서 시작점을 정의, 일반적으로 특정 노드에서 계층적 탐색을 시작하기 위해 사용
JOIN 조건: JOIN 절 내에서 부모와 자식 테이블을 연결, 부모와 자식 테이블 간의 관계를 정의,
재귀적으로 데이터를 검색
예제를 생성해보자!
테이블 생성
CREATE TABLE `comments` (
`comment_seq` int NOT NULL AUTO_INCREMENT,
`lvl` int NOT NULL DEFAULT '0',
`content` varchar(500) NOT NULL,
`parent_comment_seq` int DEFAULT NULL,
PRIMARY KEY (`comment_seq`),
KEY `comments_FK_01` (`parent_comment_seq`),
CONSTRAINT `comments_FK_01` FOREIGN KEY (`parent_comment_seq`) REFERENCES `comments` (`comment_seq`)
) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
데이터 추가
INSERT INTO comments (comment_seq, lvl, content, parent_comment_seq) VALUES (1, 0, '1번 댓글', NULL);
INSERT INTO comments (comment_seq, lvl, content, parent_comment_seq) VALUES (2, 0, '2번 댓글', NULL);
INSERT INTO comments (comment_seq, lvl, content, parent_comment_seq) VALUES (3, 1, '1번 대댓글', 1);
INSERT INTO comments (comment_seq, lvl, content, parent_comment_seq) VALUES (4, 2, '1번 대대댓글', 3);
1. 재귀 쿼리
SELECT a.*
FROM (SELECT c.comment_seq,
c.lvl,
c.content,
IFNULL(c.parent_comment_seq, c2.parent_comment_seq) AS parent_seq
FROM comments c
LEFT JOIN comments c2 on c2.parent_comment_seq = c.comment_seq ) a
ORDER BY IFNULL(parent_seq,999999999), comment_seq ;
2. CTE(Commen Table Expressions)
WITH RECURSIVE CommentHierarchy AS (
SELECT s.comment_seq,
s.lvl,
s.content,
IFNULL(s.parent_comment_seq, s1.parent_comment_seq) AS parent_seq
FROM comments s
LEFT JOIN comments s1 ON s1.parent_comment_seq = s.comment_seq
UNION
SELECT c.comment_seq,
c.lvl,
c.content,
IFNULL(c.parent_comment_seq, ch.parent_seq) AS parent_seq
FROM comments c
JOIN CommentHierarchy ch ON c.parent_comment_seq = ch.comment_seq
)
SELECT *
FROM CommentHierarchy
ORDER BY IFNULL(parent_seq, 999999999), comment_seq;