쿼리질문-경우의 수 구하기 0 6 2,461

by 김강환 [2009.04.17 08:46:36]


다음과 같이 자동차 보험상품에 관한 테이블이 있습니다.

 

WITH BOHUM_HEAD AS (
SELECT ’A’ CODE,’대인’ NAME FROM DUAL UNION ALL
SELECT ’B’ CODE,’대물’ NAME FROM DUAL UNION ALL
SELECT ’C’ CODE,’자손’ NAME FROM DUAL UNION ALL
SELECT ’D’ CODE,’자차’ NAME FROM DUAL UNION ALL
SELECT ’E’ CODE,’무보험’ NAME FROM DUAL
)

 

고객이 자동차 보험을 가입할 때 대인은 반드시 가입해야 하며 나머지는 선택입니다. 그렇다면 고객이 가입할 수 있는 모든 경우의 수는 아래와 같습니다.

 

CODE NAME
A 대인
A+B 대인+대물
A+C 대인+자손
A+D 대인+자차
A+E 대인+무보험
A+B+C 대인+대물+자손
A+B+D 대인+대물+자차
A+B+E 대인+대물+무보험
A+C+D 대인+자손+자차
A+C+E 대인+자손+무보험
A+D+E 대인+자차+무보험
A+B+C+D 대인+대물+자손+자차
A+B+C+E 대인+대물+자손+무보험
A+B+D+E 대인+대물+자차+무보험
A+B+C+D+E 대인+대물+자손+자차+무보험

 

위와 같은 결과를 보기 위해 나름 쿼리를 만들어 보았습니다.

 

SELECT
        SUBSTR(COL1,1,1)
               ||DECODE(COL2,NULL,NULL,’+’||SUBSTR(COL2,1,1))
               ||DECODE(COL3,NULL,NULL,’+’||SUBSTR(COL3,1,1))
               ||DECODE(COL4,NULL,NULL,’+’||SUBSTR(COL4,1,1))
               ||DECODE(COL5,NULL,NULL,’+’||SUBSTR(COL5,1,1)) CODE
       ,SUBSTR(COL1,2)
              ||DECODE(COL2,NULL,NULL,’+’||SUBSTR(COL2,2))
              ||DECODE(COL3,NULL,NULL,’+’||SUBSTR(COL3,2))
              ||DECODE(COL4,NULL,NULL,’+’||SUBSTR(COL4,2))
              ||DECODE(COL5,NULL,NULL,’+’||SUBSTR(COL5,2)) NAME
FROM
(
          SELECT
                MIN(DECODE(CODE,’A’,CODE))||MIN(DECODE(CODE,’A’,NAME)) COL1
                ,MIN(DECODE(CODE,’B’,CODE))||MIN(DECODE(CODE,’B’,NAME)) COL2
                ,MIN(DECODE(CODE,’C’,CODE))||MIN(DECODE(CODE,’C’,NAME)) COL3
               ,MIN(DECODE(CODE,’D’,CODE))||MIN(DECODE(CODE,’D’,NAME)) COL4
               ,MIN(DECODE(CODE,’E’,CODE))||MIN(DECODE(CODE,’E’,NAME)) COL5
 FROM BOHUM_HEAD
)
GROUP BY COL1,GROUPING SETS( 
             (NULL),(COL2),(COL3),(COL4),(COL5)
             ,(COL2,COL3),(COL2,COL4),(COL2,COL5),(COL3,COL4),(COL3,COL5),(COL4,COL5)
            ,(COL2,COL3,COL4),(COL2,COL3,COL5),(COL2,COL4,COL5)
            ,(COL2,COL3,COL4,COL5)
)
ORDER BY GROUPING(COL1)+GROUPING(COL2)+GROUPING(COL3)+GROUPING(COL4)+GROUPING(COL5) DESC
,GROUPING_ID(COL1,COL2,COL3,COL4,COL5)

 

그런데 암만 생각해 보아도 GROUPING SETS 부분이 너무 무지막한 것 같네요. 좀 더 효율적인 쿼리를 만들 수는 없을까요? 나아가 만일 상품종류가 추가되기라도 한다면 쿼리가 많이 변경되야 할 것입니다. 나중에 상품이 추가되더라도 쿼리가 변경되지 않거나 변경되더라도 최소화 할 수 있는 방법이 없을까요?

by 마농 [2009.04.17 09:54:08]
SELECT LEVEL lv
, SUBSTR(SYS_CONNECT_BY_PATH(code,'-'),2) code
, SUBSTR(SYS_CONNECT_BY_PATH(name,'-'),2) name
FROM bohum_head
CONNECT BY PRIOR code < code
ORDER BY lv, code
;

by 김강환 [2009.04.17 09:59:36]
오우 퍼펙트 역시 마농님. 그렇지 않아도 곰곰히 따져보니까 대인+자손+자차+무보험을 빼먹었던데 그것까지 완벽하게 나오네요.
START WITH CODE='A'절만 추가하면 대인은 반드시 나와야 한다는 조건까지 완벽하게 들어맞습니다. 감솨

by 서성우 [2009.04.17 10:01:48]
위의 결과 값처럼 나오고 싶으시면
위의 마농님 쿼리에
connect by
위에 start with code = 'A'
를 추가 하시면
위의 화면 처럼 나오게 할수 있겠네요

by 호야 [2009.04.17 10:04:04]
SELECT SUBSTR(SYS_CONNECT_BY_PATH(CODE,'+'),2) CODE
,SUBSTR(SYS_CONNECT_BY_PATH(NAME,'+'),2) NAME
FROM(SELECT CODE,NAME,ROWNUM RN1, ROWNUM-1 RN2,ROWNUM-2 RN3,ROWNUM-3 RN4
FROM TT)
START WITH CODE='A'
CONNECT BY PRIOR RN1=RN1-1 OR PRIOR RN1 = RN2-1
OR PRIOR RN1 = RN3-1 OR PRIOR RN1 = RN4-1
ORDER BY LENGTH(CODE)

-_- 다 했따 하고.. 들어 왔지만
이미 마농님이 퍼팩트 답변을..ㅠ..ㅠ 흑

by 김강환 [2009.04.17 11:14:45]
CONNECT BY 구문에 대해 다시 한번 생각하게 하네요. 전 지금까지 CONNECT BY절이 계층적인 구조(hierarchical)에 대해서만 유효하다고 오라클 도큐먼트에 나와있어서 물리적인 구조(EX:사원테이블에서 EMPNO와 MGRNO,부품테이블에서 부품코드와 상위부품코드 등)로 되어 있는 경우만 사용할 수 있다고 생각했습니다. 그런데 마농님 쿼리를 보니 논리적으로만 구조를 따질 수 있어도 (EX:A<B<C<D<E,1<2<3<4) CONNECT BY절은 훌륭히 제 역할을 하는 군요.

by 이재현 [2009.04.17 11:53:49]
정말 좋은 자료가 될꺼 같군요. +_+

잘 보고 갑니다...

오늘은 이걸분석하는거양~~ ㅎㅎㅎㅎ

추천 꾹~~~~~~~~~~~~~~~~~~~~~~~~~~~~
댓글등록
SQL문을 포맷에 맞게(깔끔하게) 등록하려면 code() 버튼을 클릭하여 작성 하시면 됩니다.
로그인 사용자만 댓글을 작성 할 수 있습니다. 로그인, 회원가입