CUBRID에서 ORACLE의 SYS_CONNECT_BY_PATH 구현

큐브리드 2009/06/01 07:46 Posted by 종이비행기


DDL:
CREATE TABLE "t_cat"(
"cat_no" integer PRIMARY KEY,
"parent_cat_no" integer,
"title" character varying(200) NOT NULL
);



샘플 데이터 입력:

insert into "t_cat" ("cat_no", "parent_cat_no", "title") values (1, NULL, '정치');

insert into "t_cat" ("cat_no", "parent_cat_no", "title") values (2, 1, '국내정치');

insert into "t_cat" ("cat_no", "parent_cat_no", "title") values (3, 1, '해외정치');

insert into "t_cat" ("cat_no", "parent_cat_no", "title") values (4, NULL, '경제');

insert into "t_cat" ("cat_no", "parent_cat_no", "title") values (5, 4, '국내경제');

insert into "t_cat" ("cat_no", "parent_cat_no", "title") values (6, 4, '해외경제');

insert into "t_cat" ("cat_no", "parent_cat_no", "title") values (7, 1, '기타정치');

insert into "t_cat" ("cat_no", "parent_cat_no", "title") values (8, 5, '기타경제');

insert into "t_cat" ("cat_no", "parent_cat_no", "title") values (9, 2, '정당');

insert into "t_cat" ("cat_no", "parent_cat_no", "title") values (10, 9, '한나라당');

insert into "t_cat" ("cat_no", "parent_cat_no", "title") values (11, 9, '민주당');




SYS_CONNECT_BY_PATH를 구현한 SQL:

SELECT  

        CASE WHEN cat_no4 IS NOT NULL THEN cat_no4

             WHEN cat_no3 IS NOT NULL THEN cat_no3

             WHEN cat_no2 IS NOT NULL THEN cat_no2

             WHEN cat_no1 IS NOT NULL THEN cat_no1

             END                              AS cat_no,

        CASE WHEN cat_no1 IS NOT NULL THEN cat_no1

             WHEN cat_no2 IS NOT NULL THEN cat_no2

             WHEN cat_no3 IS NOT NULL THEN cat_no3

             WHEN cat_no4 IS NOT NULL THEN cat_no4

             END                              AS root_sort,

        TO_NUMBER(NVL2(title1, '1', '0')) +

            TO_NUMBER(NVL2(title2, '1', '0')) +

            TO_NUMBER(NVL2(title3, '1', '0')) +

            TO_NUMBER(NVL2(title4, '1', '0')) AS cat_level,

        NVL2(title1, '/'+title1, '') + 

            NVL2(title2, '/'+title2, '') + 

            NVL2(title3, '/'+title3, '') + 

            NVL2(title4, '/'+title4, '')      AS cat_path

FROM 

(

        SELECT  

                t1.cat_no                     AS cat_no1,

                t2.cat_no                     AS cat_no2,

                t3.cat_no                     AS cat_no3,

                t4.cat_no                     AS cat_no4,

                t1.title                      AS title1,

                t2.title                      AS title2,

                t3.title                      AS title3,

                t4.title                      AS title4

        FROM    

                t_cat t1,

                t_cat t2,

                t_cat t3,

                t_cat t4 

        WHERE   

                t2.parent_cat_no = t1.cat_no (+)

        AND     t3.parent_cat_no = t2.cat_no (+)

        AND     t4.parent_cat_no = t3.cat_no (+)

) t

ORDER

BY      root_sort, 

        cat_path



결과:





경로 생성 문제는 Java SP(Stored Procedure)로 재귀호출 형태로 구현할 수도 있겠지만,
단위 SQL의 개수가 전체 노드의 개수만큼 생기는 문제가 있습니다.

그래서 고민하다가 outer join으로 해결하게 되었습니다.
보시면 아시겠지만 outer join을 이용해서 각 노드별로 경로를 만듭니다.
그래서, title이 null이 아닌 것만 모아서 구분자로 문자열을 만들구요.
최종적으로는 정렬을 cat_path로 하게 되는데, 루트 노드만 먼저 분류번호로 정렬하게 했습니다.

위 방법으로 노드의 최대 depth를 알고 있다면, outer join을 그 개수만큼 추가하면 되겠습니다.
즉 노드의 최대 depth에 따라 t1, t2, t3, ...로 늘리거나 줄이면 되겠습니다.
참고로, 위의 예제 SQL은 최대 depth가 4라고 가정하고 만들었습니다.

실무에 사용하시려면 최대한 테스트를 해보시고 적용하시길 부탁드리겠습니다.
문제점은 피드백(newpcraft at gmail.com) 부탁드리겠습니다.

저작자 표시 비영리 변경 금지