Programming/Oracle

[Oracle] 계층형 쿼리 (Hierarchical Query)

Isaac S. Lee 2023. 9. 4. 14:24

💡계층형 쿼리


계층형 쿼리(Hierarchical Query)는 자기 참조를 하는 테이블에서 사용하며, 레코드의 관계가 서로 간에 상하 수직 구조인 경우에 사용한다.
계층형 쿼리는 오라클 전용 쿼리이다.

자바에서는 계층형 쿼리를 트리 구조로 이해할 수 있다.

 

계층 구조

SELECT * FROM tblSelf;
홍사장
    - 김부장
        -박과장
            -최대리
                -정사원
    - 이부장
        -하과장
            -황대리
        -신과장
            -허사원

이러한 테이블을 보고 레코드의 관계가 서로 상하 수직 구조라고 한다.
이런 경우에만 계층형 쿼리를 사용할 수 있다.

부품과 부모 부품의 정보를 동시에 가져오는 작업을 해보도록 하자.

 

self join 혹은 상관 서브 쿼리 사용

SELECT
	c1.name AS 부품명,
	c2.name AS 부모부품명
FROM tblComputer c1				--부품(자식)
	INNER JOIN tblComputer c2	--부모부품(부모)
		ON c1.pseq = c2.seq;

self join은 자식과 부모 관계만을 인식할 수 있는 반면에, 계층형 쿼리는 세대(단계) 별로 테이블을 확인할 수 있다.

계층형 쿼리를 실습해 보며 사용법을 익혀보도록 하자.

 

💡계층형 쿼리의 사용

1. start with 절 + connect by절

2. 계층형 쿼리에서만 사용 가능한 의사 컬럼들

  a. prior: 자기와 연관된 부모 레코드를 참조

  b. level: 세대수(depth, generation)

 

start with절 + connect by절

SELECT
	*
FROM tblComputer
	START WITH 조건		--루트 레코드를 찾는 조건
		CONNECT BY 조건	--현재 레코드와 부모 레코드를 연결하는 조건

start with절 + connect by절은 위와 같이 작성한다.

만약 where절을 사용할 경우 connect by절 다음에 작성하면 된다.

 

prior 예약어

SELECT
	*
FROM tblComputer
	START WITH seq = 1					--루트 레코드를 찾는 조건
		CONNECT BY pseq = PRIOR seq;	--현재 레코드와 부모 레코드를 연결하는 조건

계층형 쿼리는 테이블이 하나이기 때문에 본인의 부모 부품 번호와 부모 부품 번호의 기본키 역할을 하는 번호를 작성한다.
이때 부모 부품 번호의 기본키 역할을 하는 게 없으므로 prior 예약어를 붙여 가상 컬럼으로서 부모 테이블의 레코드를 참조하게 한다.

 

SELECT
	seq AS 번호,
	name AS 부품명,
	PRIOR name AS 부모부품명
FROM tblComputer
	START WITH seq = 1
		CONNECT BY pseq = PRIOR seq;

select절에서 prior 예약어를 붙였기 때문에 부모의 부품명을 가져온다.

 

level 예약어

SELECT
	seq AS 번호,
	lpad(' ', (LEVEL - 1) * 10) || name AS 부품명,
	PRIOR name AS 부모부품명,
	LEVEL
FROM tblComputer
	START WITH seq = 1
		CONNECT BY pseq = PRIOR seq;

lpad의 들여 쓰기 기능으로 계층구조를 표현하였다.

 

특정 세대만 확인하기

SELECT
	seq AS 번호,
	lpad(' ', (LEVEL - 1) * 10) || name AS 부품명,
	PRIOR name AS 부모부품명,
	LEVEL
FROM tblComputer
	START WITH seq = 2
		CONNECT BY pseq = PRIOR seq;

start with절의 값을 수정하여 특정 계층만 확인할 수 있다.

seq = 2로 수정하였더니 컴퓨터가 아니라 본체의 계층을 보여준다.

 

직속상사 확인하기

SELECT
	seq AS 번호,
	lpad(' ', (LEVEL - 1) * 10) || name 이름,
	PRIOR name AS 직속상사,
	LEVEL
FROM tblSelf
	START WITH seq = 1
		CONNECT BY super = PRIOR seq;

  • prior: 부모 레코드 참조 > 직속 상사
  • connect_by_root: 최상위 레코드 참조 > 홍사장
  • connect_by_isleaf: 자식이 있는지를 검사(말단노드)
  • sys_connect_by_path: 계층 구조를 출력
SELECT
	seq AS 번호,
	lpad(' ', (LEVEL - 1) * 10) || name 이름,
	PRIOR name AS 직속상사,
	connect_by_root name,
	connect_by_isleaf name
FROM tblSelf
	START WITH seq = 1
		CONNECT BY super = PRIOR seq;

 

정렬하기

SELECT
	seq AS 번호,
	lpad(' ', (LEVEL - 1) * 10) || name AS 부품명,
	PRIOR name AS 부모부품명,
	LEVEL
FROM tblComputer
	START WITH seq = 1
		CONNECT BY pseq = PRIOR seq
			--ORDER BY name ASC
			ORDER siblings BY name ASC;

계층을 정렬할 때에는 order by절에 siblings를 사용한다.