2016년 4월 5일 화요일

오라클 wm_concat 정렬

오라클 row 데이터를 하나의 로우로 합칠려다 보니 문제가 많다. ㅜㅜ

1. LISTAGG(ADDITION_INFO_T, ' | ') WITHIN GROUP(ORDER BY SEQ)

LISTAGG 함수는 ROW 단위별 연결 문자 지정이 가능하고 정렬도 가능하다.
하지만 OTL 문자열이 VARCHAR2 4000 자를 초과하면 에러가 난다.

그래서 대신 할수 있는 함수가 무엇일까?

WM_CONCAT 두둥 근데 정렬이 ㅠㅠ 구분자가 ㅠㅠ

정렬은 검색으로 찾았다. 근데 구분자는 ㅠㅠ

참고로 XMLAGG 나 LISTAGG 는 문자열 크기 초과에러 발생한다 ㅠㅠ

with tbl as
(
    select 1 seq , '20110801' ymd, 't' gubun, 'input1' title from dual
    union select 2 seq , '20110802' ymd, 't' gubun, 'input2' title from dual
    union select 3 seq , '20110802' ymd, 't' gubun, 'input3' title from dual
    union select 4 seq , '20110802' ymd, 't' gubun, 'input4' title from dual
    union select 5 seq , '20110802' ymd, 't' gubun, 'input5' title from dual
    union select 6 seq , '20110804' ymd, 'c' gubun, 'input6' title from dual
)
select
    ymd,wm_concat(seq||'||'||title) as seq_title
from
    tbl
group by ymd
제가 할려는게 같은 날짜의 title 를 seq 순서대로 뽑아내는건대요
위에 쿼리를 돌려보면
20110801    1||input1
20110802    2||input2,4||input4,5||input5,3||input3   <== 여기가 문제임
20110804    6||input6

이런식으로 나옵니다. 즉 2,3,4,5 이런순으로 나와야 하는대 엉뚱하게 3이 젤 나중에 나와버립니다.
어떻게 해야 할까요? 도움 주시면 감사하겠습니다...
이 글에 대한 댓글이 총 1건 있습니다.
wm_concat 간단하면서도 강력한 기능 정말 좋은데...
한가지 아쉬운 점이 정렬 기능이 없다는 거죠...
XmlAgg(9i) 나 ListAgg(11g) 를 이용하시면 됩니다.

SELECT ymd
     , SUBSTR(XMLAGG(XMLELEMENT(x, ',', seq, '||', title) ORDER BY seq)
       .EXTRACT('//text()'), 2) v_9i
     , wm_concat(seq||'||'||title) v_10g
     , LISTAGG(seq||'||'||title, ',') WITHIN GROUP(ORDER BY seq) v_11g
  FROM tbl
 GROUP BY ymd
 ORDER BY ymd
;

wm_concat를 이용해 정렬하고자 한다면..
인라인뷰에서 분석함수의 정렬기능을 이용하신후 밖에서 걸러내시면 됩니다.

SELECT ymd
     , seq_title
  FROM (SELECT ymd, seq
             , wm_concat(seq||'||'||title)
               OVER(PARTITION BY ymd ORDER BY seq) seq_title
             , MAX(seq) OVER(PARTITION BY ymd) max_seq
          FROM tbl
        )
 WHERE seq = max_seq
 ORDER BY ymd
;

Connect_By_Path(9i)를 이용하는 방법도 있는데 더 복잡하고 성능도 안좋아요.

SELECT ymd
     , SUBSTR(SYS_CONNECT_BY_PATH(seq||'||'||title, ','), 2) seq_title
  FROM (SELECT ymd, seq, title
             , ROW_NUMBER() OVER(PARTITION BY ymd ORDER BY seq) rn
             , COUNT(*) OVER(PARTITION BY ymd) cnt
          FROM tbl
        )
 WHERE rn = cnt
 START WITH rn = 1
 CONNECT BY PRIOR ymd = ymd
        AND PRIOR rn + 1 = rn
;

댓글 없음:

댓글 쓰기