본문 바로가기
DATABASE/ORACLE

[ORACLE SQL 문제] 경우의 수 구하기

by sjs_2215 2020. 3. 4.

문제 링크: http://www.gurubee.net/lecture/2196

(내 댓글 참고)

 

[퀴즈] 경우의 수 구하기

  이번 퀴즈로 배워보는 SQL 시간에는 주어진 코드 리스트를 이용해 조합 가능한 모든 경우의 수를 구하는 쿼리를 어떻게 작성하는지에 대해 알아본..

www.gurubee.net


[내가 생각한 방법들] 

 

1. 구글링 결과 WM_CONCAT을 알게 돼서 써봄.. - 결과 터무니없음

 

WITH TEST AS
(
    SELECT 'A' code FROM dual
    UNION ALL SELECT 'B' FROM dual
    UNION ALL SELECT 'C' FROM dual
)
SELECT   WM_CONCAT(T.CODE)
FROM     TEST T
WHERE    1 = 1
--AND      T.CODE IN ('B', 'A')
;

 

2. 최근에 알게 된 LEAD, LAG 함수에 꽂혀서 노가다 방식을 생각해봄. - 결과는 터무니없음

 

SELECT   T.CODE
FROM     TEST T
UNION ALL
SELECT   T.CODE || ',' || LEAD(T.CODE) OVER (ORDER BY T.CODE) 
FROM     TEST T
UNION ALL
SELECT   T.CODE || ',' || LEAD(T.CODE) OVER (ORDER BY T.CODE) || ',' || LEAD(T.CODE) OVER (ORDER BY T.CODE) 
FROM     TEST T
;

 

3. 셀프 조인을 해 봄 -> AA BB CC와 같은 값을 어떻게 없애야 하는지 생각을 더 안 함...

부등호 조인 배웠는데!!! 너무 아깝

 

SELECT   *
FROM     TEST T1, TEST T2
WHERE    1 = 1
;

 


[해설 보고 완성한 쿼리들]

 

  • 결과 테이블 1 답(하수 VER.) -> CROSS JOIN 이용

-> 셀프 조인과, 부등호 조인 보고 바로 도출한 쿼리

 

WITH TEST AS
(
    SELECT 'A' code FROM dual
    UNION ALL SELECT 'B' FROM dual
    UNION ALL SELECT 'C' FROM dual
)
SELECT   *
FROM     TEST T1
UNION ALL
SELECT   T1.CODE || ',' || T2.CODE CODE
FROM     TEST T1, TEST T2
WHERE    1 = 1
AND      T1.CODE < T2.CODE
UNION ALL
SELECT   WM_CONCAT(T.CODE)
FROM     TEST T
;

 

 

  • 결과 테이블 1 답 (고수 VER.) -> 계층구조 쿼리 이용

-> TEST 테이블에는 부모 - 자식 칼럼이 따로 주어져있지 않지만, 우리가 정해서 SYS_CONNECT_BY_PATH를 이용해먹으면 됨
->  AB/AC/BC/ABC를 부모-자식 관계라고 생각해서 [부모 코드가 자식 코드보다 작다는 공통 조건을] 주면 됨!
(이 조건은 이미 Cross Join 방법에서도 이미 사용되었던 조건)

 

WITH TEST AS
(
    SELECT 'A' code FROM dual
    UNION ALL SELECT 'B' FROM dual
    UNION ALL SELECT 'C' FROM dual
)
SELECT   CODE 
       , LEVEL
       , SYS_CONNECT_BY_PATH(CODE, '-') PATH
FROM     TEST
CONNECT BY PRIOR CODE < CODE
;

 

  • 결과 테이블 2 답

나는 CONNECT BY 조건을 <= 로 생각함  (실패)
결과 테이블 2는 순서까지 고려한 것이므로 [부모 코드가 자식 코드와 다르면] 연결 조건이 성립됨.

 

WITH TEST AS
(
    SELECT 'A' code FROM dual
    UNION ALL SELECT 'B' FROM dual
    UNION ALL SELECT 'C' FROM dual
)
SELECT   CODE 
       , LEVEL
       , SYS_CONNECT_BY_PATH(CODE, '-') PATH
FROM     TEST
CONNECT BY NOCYCLE PRIOR CODE != CODE
;

'계층 구조 쿼리' 이해를 위한 간단한 예제

 

WITH test AS
(
 SELECT 'A' 코드, '' 부모코드 FROM dual
 UNION ALL SELECT 'B', 'A' FROM dual
 UNION ALL SELECT 'C', 'B' FROM dual
)
SELECT     코드
         , 부모코드
         , LEVEL
         , SYS_CONNECT_BY_PATH(코드, '-') 계층경로
FROM       TEST
START WITH 부모코드 IS NULL
CONNECT BY PRIOR 코드=부모코드
;

 

LEVEL (계층의 DEPTH를 알려줌)
LEVEL을 쓰기 위해선 CONNECT BY를 같이 써야 하고, 이는 JOIN 조건(계층구조 쿼리 VER)이라고 생각하면 됨
PRIOR는 상위 노드의 값을 참조하겠다는 의미. 
START WITH에 계층구조의 시작 조건을 기술해줌. 

Comments