Notice: Function _load_textdomain_just_in_time was called incorrectly. Translation loading for the ultimate-member domain was triggered too early. This is usually an indicator for some code in the plugin or theme running too early. Translations should be loaded at the init action or later. Please see Debugging in WordPress for more information. (This message was added in version 6.7.0.) in /ledcorps/www/wp/wp-includes/functions.php on line 6114 3.3 계층구조 쿼리의 응용 – 대나무숲

3.3 계층구조 쿼리의 응용

출처 http://www.gurubee.net/lecture/2681

하위에서 상위로 누적 합계 구하기

아래는 현재행을 시작점으로 하위에서 상위로 누적합계를 구하는 예제이다.

  • [그림] 계산예시
SELECT empno
     , LEVEL lv
     , LPAD(' ', (LEVEL-1)*2, ' ') || ename AS ename
     , sal
     , (SELECT SUM(sal)
          FROM emp
         START WITH empno = a.empno
         CONNECT BY PRIOR empno = mgr
        ) sum_sal
  FROM emp a
 START WITH mgr IS NULL
 CONNECT BY PRIOR empno = mgr
;
 
 
  EMPNO         LV ENAME                       SAL    SUM_SAL
------- ---------- -------------------- ---------- ----------
   7839          1 KING                       5000      29025
   7566          2   JONES                    2975      10875
   7788          3     SCOTT                  3000       4100
   7876          4       ADAMS                1100       1100
   7902          3     FORD                   3000       3800
   7369          4       SMITH                 800        800
   7698          2   BLAKE                    2850       9400
   7499          3     ALLEN                  1600       1600
   7521          3     WARD                   1250       1250
   7654          3     MARTIN                 1250       1250
   7844          3     TURNER                 1500       1500
   7900          3     JAMES                   950        950
   7782          2   CLARK                    2450       3750
   7934          3     MILLER                 1300       1300

현재행을 시작점으로 스칼라서브쿼리에서 계층구조를 전개하여 합산을 한다.

CONNECT BY LEVEL을 이용한 테스트 샘플데이터 생성

프로젝트 진행시 테스트 데이터 생성이 필요한 경우가 있는데 CONNECT BY LEVEL을 활용하면 손쉽게 테스트 샘플 데이터를 생성 할 수 있다.

아래 예제와 같이 CONNECT BY LEVEL을 사용하면, 특정 LEVEL이 될 때 까지 ROW를 출력하는 것을 알 수 있다.

-- 10개의 ROW를 출력하는 예제이다. 
SELECT LEVEL FROM DUAL CONNECT BY LEVEL <= 10;
 
-- 10개의 ROW가 출력된다. 
LEVEL
-------
      1
      2
      3
      4
...
     10

위 CONNECT BY LEVEL의 원리를 이용하여 아래와 같이 테스트 샘플데이터를 만들어 보자

-- 10 만건의 데이터를 가지는 emp_sample 테이블을 생성하는 예제이다. 
CREATE TABLE emp_sample AS
SELECT -- 1. EMPNO(Unique 컬럼)
       LEVEL empno,       
       -- 2. JOB(천만건 데이터를 10개 그룹으로 분류)
       'SALESMAN_'||CHR(65 + MOD(LEVEL , 10)) job,
       -- 3. HIREDATE(금일+9일까지) 
       SYSDATE +  MOD(LEVEL , 10) hiredate,
       -- 4. DEPTNO (0, 10, 20, 30, 40)
       MOD(LEVEL ,5)*10 deptno
FROM   DUAL
CONNECT BY LEVEL <= 100000;
 
-- 테이블과 데이터가 정상적으로 생성되었는지 확인해 보자
SELECT * FROM emp_sample WHERE ROWNUM < 10;
 
 
EMPNO    JOB        HIREDATE    DEPTNO
----- ----------- -------- ----------
     1 SALESMAN_B  11/06/28         10
     2 SALESMAN_C  11/06/29         20
     3 SALESMAN_D  11/06/30         30
     4 SALESMAN_E  11/07/01         40
...

경우의 수 조회

이번 예제는 그림과 같이 (A, B, C) 3개 코드 조합으로 나올 수 있는 모든 경우의 수를 조회하는 예제이다.

  • [그림] 경우의 수

아래는 계층구조쿼리를 사용하지 않고, UNION ALL을 이용하여 작성하였다. 아래 쿼리는 self 조인과 UNION ALL 조합의 한계가 있다. 코드의 개수가 늘어날 경우 SQL 수정이 불가피 하다.

WITH test AS
(
SELECT 'A' code FROM dual
UNION ALL SELECT 'B' FROM dual
UNION ALL SELECT 'C' FROM dual
)
SELECT a.code
  FROM test a
 UNION ALL
SELECT a.code ||'-'|| b.code AS code
  FROM test a
     , test b
 WHERE a.code < b.code
 UNION ALL
SELECT a.code ||'-'|| b.code ||'-'|| c.code AS code
  FROM test a
     , test b
     , test c
 WHERE a.code < b.code
   AND b.code < c.code
;
 
 
CODE
---------------
A
B
C
A-B
A-C
B-C
A-B-C
 
7 rows selected.

코드의 개수가 늘어날 경우 SQL 수정이 불가피하다.

아래는 계층구조쿼리를 사용하여 경우의 수를 조회한 예제이다.

WITH test AS
(
SELECT 'A' code FROM dual
UNION ALL SELECT 'B' FROM dual
UNION ALL SELECT 'C' FROM dual
)
SELECT SUBSTR(SYS_CONNECT_BY_PATH(code, '-'), 2) code
  FROM test
 CONNECT BY PRIOR code < code
 ORDER BY LEVEL, code
;
 
CODE
-----------------
A
B
C
A-B
A-C
B-C
A-B-C
 
7 rows selected.

부등호 조건(PRIOR CODE < CODE)을 이용한 계층 전개 계층전개 조건이 반드시 이퀄(=)조건일 필요는 없다.

순서까지 고려한 모든 경우의 수

이번 예제는 순서까지 고려한 모든 경우의 수이다.

  • [그림] 모든경우의 수
WITH test AS
(
SELECT 'A' code FROM dual
UNION ALL SELECT 'B' FROM dual
UNION ALL SELECT 'C' FROM dual
)
SELECT SUBSTR(SYS_CONNECT_BY_PATH(code, '-'), 2) code
  FROM test
 CONNECT BY NOCYCLE PRIOR code != code
 ORDER BY LEVEL, code
;
 
 
CODE
-------------------
A
B
C
A-B
A-C
B-A
B-C
C-A
C-B
A-B-C
A-C-B
B-A-C
B-C-A
C-A-B
C-B-A
 
15 rows selected.
  • – 부등호(!=) 사용시 순환구조 발생 (예: A-B-C-A-…)
  • – NOCYCLE 사용으로 에러 방지 (예: A-B-C (여기까지만) -A-…)

답글 남기기 0

Your email address will not be published. Required fields are marked *