더북(TheBook)

③ 컬럼을 로우로 변환하기

이젠 반대로 ex7_2 테이블을 조회해 컬럼을 로우로 바꿔볼 텐데, 계층형 쿼리를 사용하면 쉽게 변환할 수 있다. 예를 들어 90번 부서에는 3명의 사원이 속해 있으므로 로우로 변환하면 3개의 로우가 만들어져야 한다. 그럼 어떻게 3개의 로우로 만들 수 있을까?

3명의 사원 이름이 구분자인 콤마(,)로 구분되어 있고 구분자 개수가 2인데, 맨 끝에 콤마를 한 개 더 붙여 3개로 만든 다음 이를 레벨로 활용하면 CONNECT BY LEVEL 구문으로 3개의 로우를 만들어 낼 수 있다.

입력

    SELECT empnames,
           LEVEL as lvl
     FROM ( SELECT empnames || ',' as empnames,
                   LENGTH(empnames) ori_len,
                   LENGTH(REPLACE(empnames, ',', '')) new_len
              FROM ex7_2
             WHERE department_id = 90
           )
     CONNECT BY LEVEL <= ori_len - new_len + 1;

결과

    EMPNAMES                                 LVL
    ---------------------------------------- --------
    Lex De Haan,NeenaKochhar,Steven King,    1
    Lex De Haan,NeenaKochhar,Steven King,    2
    Lex De Haan,NeenaKochhar,Steven King,    3

먼저 서브 쿼리를 살펴보면 ori_len은 3명의 원래 문자열 길이, new_len은 원 문자열에서 콤마를 제외한 문자열 길이를 반환한다. 따라서 (ori_len-new_len) 값에 1을 더하면 총 사원 수(3)가 되고 CONNECT BY LEVEL에 명시하면 위와 같이 3개의 로우를 만들어 낼 수 있다. 이제 할 일은 각 레벨별로 사원 이름을 분리해 내기만 하면 된다. 즉 1레벨은 맨 처음 사원, 2레벨은 두 번째, 3레벨은 세 번째 사원명을 분리해 내야 한다.

입력

    SELECT empnames,
           DECODE(level, 1, 1, INSTR(empnames, ',', 1, LEVEL-1)) start_pos,
           INSTR(empnames, ',', 1, LEVEL) end_pos,
           LEVEL as lvl
      FROM (  SELECT empnames || ',' as empnames,
                     LENGTH(empnames) ori_len,
                     LENGTH(REPLACE(empnames, ',', '')) new_len
                FROM ex7_2
               WHERE department_id = 90
            )
      CONNECT BY LEVEL <= ori_len - new_len + 1;

결과

    EMPNAMES                                START_POS    END_POS    LVL
    --------------------------------------- ------------ ---------- -------
    Lex De Haan,NeenaKochhar,Steven King,   1            12         1
    Lex De Haan,NeenaKochhar,Steven King,   12           26         2
    Lex De Haan,NeenaKochhar,Steven King,   26           38         3

콤마를 기준으로 레벨별로 start_pos는 시작 위치, end_pos는 끝 위치이며 이를 이용하면 다음과 같이 사원명을 분리해 낼 수 있다.

입력

    SELECT REPLACE(SUBSTR(empnames, start_pos, end_pos - start_pos), ',', '') AS emp
    FROM ( SELECT empnames,
                  DECODE(level, 1, 1, INSTR(empnames, ',', 1, level-1)) start_pos,
                  INSTR(empnames, ',', 1, LEVEL) end_pos,
                  LEVEL as lvl
          FROM (  SELECT empnames || ',' as empnames,
                         LENGTH(empnames) ori_len,
                         LENGTH(REPLACE(empnames, ',', '')) new_len
                    FROM ex7_2
                   WHERE department_id = 90
               )
          CONNECT BY LEVEL <= ori_len - new_len + 1
    ) ;

결과

    EMP
    ----------------
    Lex De Haan
    NeenaKochhar
    Steven King

start_pos와 end_pos 값을 활용해 문자열을 잘랐고 최종적으로 REPLACE 함수를 써서 콤마를 제거해 각 사원 이름을 추출해 냈다. 콤마로 구분된 문자열에서 각 사원명을 분리해 내는 로직이 약간 복잡하지만 차근차근 살펴보면 이해하는데 그리 어렵지 않을 것이다. 여기에서 중요한 점은 계층형 쿼리로 사원 수에 맞게 콤마를 한 개 추가하고 이 콤마 수를 레벨로 활용해 컬럼을 로우 형태로 만들어 낸 것이다.

신간 소식 구독하기
뉴스레터에 가입하시고 이메일로 신간 소식을 받아 보세요.