[순번 생성]
계층 쿼리를 사용하여 순번을 가진 테이블을 생성할 수 있다.
행 복제 시 해당 기법을 활용할 수 있다.
아래 쿼리는 100까지의 순번을 반환한다.
START WITH 절을 생략했기 때문에 DUAL 테이블의 전체 행이 루트 노드로 생성된다.
DUAL 테이블이 1행이므로 루트 노드가 1행으로 생성되고,
1행과 1행을 카티션 곱합 결과는 1행이므로 LEVEL <= 100 조건을 만족할 때까지 1행씩 레벨이 증가하는 것이다.
SELECT LEVEL AS LV
FROM DUAL
CONNECT BY LEVEL <= 100;
아래와 같이 XMLTABLE 함수를 사용해도 동일한 결과를 얻을 수 있다.
SELECT ROWNUM AS RN
FROM XMLTABLE ('1 TO 100');
[변경이력]
계층 쿼리를 응용하면 값의 변경 이력을 확인할 수 있따.
예제를 위해 아래와 같이 테이블을 생성하자
DROP TABLE T1 PURGE;
CREATE TABLE T1 (
YM VARCHAR2(6) -- 연월
, BF VARCHAT2(4) -- 변경 전 코드
, AF VARCHAR2(4) -- 변경 후 코드
);
INSERT INTO T1 VALUES ('205001', 'A', 'B');
INSERT INTO T1 VALUES ('205001', 'I', 'J');
INSERT INTO T1 VALUES ('205001', 'X', 'Y');
INSERT INTO T1 VALUES ('205004', 'B', 'C');
INSERT INTO T1 VALUES ('205004', 'J', 'K');
INSERT INTO T1 VALUES ('205007', 'C', 'D');
COMMIT;
아래 표는 코드 변경 이력을 표현하고 있다
A 코드는 2050년 1월에 B 코드로, B 코드는 2050년 4월에 C 코드로, C 코드는 2050년 7월에 D 코드로 변경되었다.
최초 - 205001 - 205004 - 205007
A - B - C - D
I - J - K
X - Y
아래 쿼리는 코드의 최종 변경 코드를 조회한다.
START WITH 절이 생략되어 전체 행이 루트 노드로 생성된다.
CONNECT_BY_ROOT 연산자로 루트 노드를 조회하고, CONNECT_BY_ISLEAF 슈도 칼럼으로 리프 노드만 조회했다.
SELECT BF, AF, YM
FROM (SELECT YM, CONNECT_BY_ROOT BF AS BF, AF, CONNECT_BY_ISLEAF AS LF
FROM T1
CONNECT BY BF = PRIOR AF)
WHERE LF = 1
ORDER BY 1;
아래 쿼리는 최초 코드의 변경 정보를 조회한다.
최초 코드로 루트 노드를 생성하기 위해
START WITH 절에서 변경 전 코드가 존재하지 않는 행을 조회한 후 순방향으로 계층을 전개했다.
SELECT BF, CD, YM, CD
FROM (SELECT CONNECT_BY_ROOT BF AS BF
, SUBSTR (SYS_CONNECT_BY_PATH (AF, ','), 2) AS CD
, SUBSTR (SYS_CONNECT_BY_PATH (YM, ','), 2) AS YM
, LEVEL AS CN
, CONNECT_BY_ISLEAF AS LF
FROM T1 A
START WITH NOT EXISTS (SELECT 1 FROM T1 X WHERE X.AF = A.BF)
CONNECT BY BF = PRIOR AF)
WHERE LF = 1
ORDER BY 1;
아래 쿼리는 최종 코드의 변경 정보를 조회한다.
최종 코드로 루트 노드를 생성하기 위해 START WITH 절에서 변경 후 코드가 존재하지 않는 행을 조회한 후 역방향으로 계층을 전개했다.
SELECT AF, CD, YM, CN
FROM (SELECT CONNECT_BY_ROOT AF AS AF
, SUBSTR (SYS_CONNECT_BY_PATH (BF, ','), 2) AS CD
, SUBSTR (SYS_CONNECT_BY_PATH (YM, ','), 2) AS YM
, LEVEL AS CN
, CONNECT_BY_ISLEAF AS LF
FROM T1 A
START WITH NOT EXISTS (SELECT 1 FROM T1 X WHERE X.BF = A.AF)
CONNECT BY AF = PRIOR BF)
WHERE LF = 1
ORDER BY 1;
[생성순서]
계층 쿼리를 사용하면 순차적으로 계산되는 계정의 생성 순서를 결정할 수 있다.
예제를 위해 아래와 같이 테이블을 생성
DROP TABLE T1 PURGE;
CREATE TABLE T1 (
CD VARCHAR2(1) -- 계정
, C1 VARCHAR2(1) -- 계산계정1
, C2 VARCHAR2(1) -- 계산계정2
, C3 VARCHAR2(1) -- 계산계정3
, C4 VARCHAR2(1) -- 계산계정4
);
INSERT INTO T1 VALUES ('A', 'B', 'C', 'D', 'E');
INSERT INTO T1 VALUES ('B', 'F', 'G', 'H', NULL);
INSERT INTO T1 VALUES ('C', 'I', 'J', NULL, NULL);
INSERT INTO T1 VALUES ('D', 'K', NULL, NULL, NULL);
INSERT INTO T1 VALUES ('E', 'B', 'C', NULL, NULL);
INSERT INTO T1 VALUES ('F', 'C', 'D', NULL, NULL);
COMMIT;
T1 테이블의 데이터를 아래와 같이 표현할 수 있다.
계정(CD)은 계산계정(C1, C2, C3, C4)으로 계산된다.
계정 A는 계정 B, C, D, E로 계산되고, 계정 B는 계정 F, G, H로 계산된다.
계정 A를 계산하기 위해서는 계정 B를 먼저 생성해야 한다.
CD - C1 - C2 - C3 - C4
A - B - C - D - E
B - F - G - H
C - I - J
D - K
E - B - C
F - C - D
아래 쿼리로 계정의 생성 순서를 결정할 수 있다.
먼저 생성할 필요가 없는 계산계정으로 생성되는 계정을 루트 노드로 생성한 후 역방향으로 계층을 전개했다.
계정 A는 다섯 번째로 생성해야 한다.
SELECT CD, MAX (LEVEL) AS LV
FROM T1 A
START WITH NOT EXISTS (SELECT 1 FROM T1 X WHERE X.CD IN (A.C1, A.C2, A.C3, A.C4))
CONNECT BY PRIOR CD IN (C1, C2, C3, C4)
GROUP BY CD
ORDER BY 2, 1;
위 쿼리의 CONNECT BY 절은 아래와 같이 해석된다.
CONNECT BY (C1 = PRIOR CD OR C2 = PRIOR CD OR C3 = PRIOR CD OR C4 = PRIRO CD)
[누적 연산]
재귀 서브 쿼리 팩토링을 사용하면 상위 노드의 값을 누적 연산할 수 있다.
아래 쿼리는 상위 노드의 SAL을 하위 노드로 누적 집계한다.
WITH W1 (EMPNO, ENAME, MGR, SAL, LV, C1) AS (
SELECT EMPNO, ENAME, MGR, SAL, 1 AS LV, SAL AS C1
FROM EMP
WHERE MGR IS NULL
UNION ALL
SELECT C.EMPNO, C.ENAME, C.MGR, C.SAL, P.LV + 1 AS LV, P.C1 + C.SAL AS C1
FROM W1 P, EMP C
WHERE C.MGR = P.EMPNO)
SEARCH DEPTH FIRST BY EMPNO SET SO
SELECT LV, EMPNO, LPAD (' ', LV - 1, ' ') || ENAME AS ENAME, MGR, SAL, C1
FROM W1
ORDER BY SO;
계층 쿼리 절은 부모 노드의 값만 참조할 수 있기 때문에 누적 연산이 불가능하다.
SELECT LEVEL AS LV, EMPNO, LPAD (' ', LEVEL - 1, ' ') || ENAME AS ENAME, MGR
, SAL, SAL + PRIOR SAL AS C1
FROM EMP
START WITH MGR IS NULL
CONNECT BY MGR = PRIOR EMPNO;
'IT' 카테고리의 다른 글
[오라클, Oracle] PIVOT 절과 UNPIVOT 절 - 활용 예제 (0) | 2020.05.02 |
---|---|
[오라클, Oracle] PIVOT 절과 UNPIVOT 절 (0) | 2020.05.02 |
[오라클, Oracle] 계층 쿼리 (hierarchical query) - 고급 주제 (0) | 2020.05.01 |
[오라클, Oracle] 계층 쿼리 (hierarchical query) - 재귀 서브 쿼리 팩토링 (0) | 2020.05.01 |
[오라클, Oracle] 계층 쿼리 (hierarchical query) - 계층 쿼리 절 (0) | 2020.05.01 |