1000개 이상의 row에 대한 피벗은 어떻게 할 수 있을까요? 1 16 16,147

by 손님 [2013.04.01 15:24:26]


약 2000만 건 정도의 row가 있고,
이것들에 대해 특정 컬럼을 기준으로 grouping 및 컬럼 pivoting(한 개의 컬럼에 우측으로 concat)을 진행하려 합니다.

진행 중에,
약 5000 여 개의 row들이 한 개의 row로 pivot 되어야 하는 상황이 발생 했는데요,
기존에 사용하던 decode방식으로는 안 되는 것 같습니다.

PL/SQL 내에서 커서 돌리면서 CLOB변수에 concat하면서 처리하는 방법이 있을 것 같은데,
2000만 건에 대한 커서는 너무 오래 걸릴 것 같습니다.

혹시 좋은 방법이 있을까요?
고수님들의 답변 부탁 드리겠습니다.

감사합니다.

by 디케이 [2013.04.01 15:40:39]


오라클 DB의 경우 버전에 따라 WM_CONCAT, XMLAGG, LISTAGG를 사용할 수 있습니다.

예)
   SELECT LISTAGG(컬럼이름, '연결문자') WITHIN GROUP(ORDER BY 오더순서)
    FROM 테이블명
GROUP BY 컬럼명

나머지도 본 사이트 조회해보시면 사용법을 알 수 있을 겁니다.
참고로, 이전에 XMLAGG(10g)를 사용시 길이가 너무 길어지니까 에러가 발생했는것 같아요..
몇바이트때 에러가 발생하는지 정확히는 모르겠지만..^^

by 손님 [2013.04.01 15:59:01]
답변 감사드립니다.
알려주신 방법을 사용해 봤는데요,
"ORA-01489 문자열 연결의 결과가 너무 깁니다"
에러가 발생하네요~
다른 방법을 찾아야 할 것 같네요~~ㅜㅜ

참고로 저는 11g 사용 중입니다.

감사합니다.

by 마농 [2013.04.01 16:07:59]
http://www.gurubee.net/article/55512
이 방법은 Varchar2(4000) 이 한계입니다.
한계를 벗어나려면 Clob 으로 Concat 하셔야 합니다.

by 손님 [2013.04.01 16:21:40]
마농님 답변 감사드립니다.

저도 셋 다 해봤는데요,
listagg -> 문자열 길이 에러
wm_concat -> 문자열 길이 에러는 안 생기나, 정렬이 안 됨.
xmlagg -> 문자열 버퍼 에러

셋 다 사용은 어렵습니다.

결국은, 커서가 답일 것 일까요?? ㅠㅠ

아무튼 조언 감사드립니다.

by 디케이 [2013.04.01 16:21:24]

LISTAGG가 한계가 있군요..
저두 하나 배웠네요..^^

이전에 이렇게 사용한적도 있네요.. 해결되었으면 좋겠네요.
SUBSTR(XMLAgg(XMLElement(컬럼, ',', 컬럼) ORDER BY 컬럼).Extract('//text()').GETCLOBVAL(),2)

by 손님 [2013.04.01 16:33:39]
결국,

wm_concat(X) over (partition by A order by B)

이 방법을 써서 겨우 해결 했네요~~

아무튼,
디케이님, 마농님 감사드립니다~

by 마농 [2013.04.03 10:38:29]
.getCLOBval() 로 테스트 해보니 잘 되는군요.

by 마농 [2013.04.01 16:55:01]
wm_concat 에서만 에러가 안났다는건 이해 할 수 없는 결과네요.
혹시 토드같은 부분패치(500건) 툴에서 조회하셨나요?
500건까지는 에러 안나고 정상조회 되다가 스크롤 내리면 에러날수 있습니다.

by 미소애비 [2013.04.01 17:24:00]
본 내용은,
5000건이 1건으로 합쳐지냐 마냐의 문제이기 때문에,
500건 조회 내용과는 관계가 없어 보입니다.

다만,
마농님께서 의아해 하시는건,
어떻게 wm_concat만 Varchar2(4000)을 넘어서서 합쳐지는게 가능하냐? 인 것 같은데요....
저도 잘 모르지만,

제가 해 본 결과에 따르면,
vm_concat은 CLOB으로 확실히 잘 합쳐졌습니다.
의심이 생겨서 CLOB으로 합친 후 파싱해서 카운트 다시 해 봤는데요,
5000개가 넘는 컬럼들이 누락 없이 잘 합쳐져 있었습니다.

아무튼 감사합니다~~~

죄송한 얘기이지만,
맨날 회원 가입 안 하고 손님으로만 사용하다가,
이번에 회원 가입도 했습니다.

혹시 Oracle Spatial 많이 사용하시는 분들 계시다면,
많은 정보 교류가 이루어졌으면 합니다~
감사합니다.

by 마농 [2013.04.01 18:01:56]
-- 어찌 성공하신건지 궁금하네요.
-- 저는 아무리 테스트해봐도 오류나는데요.
WITH t AS
(
SELECT LPAD('1', 2000, '1') v FROM dual
UNION ALL SELECT LPAD('2', 2000, '2') FROM dual
UNION ALL SELECT LPAD('3', 2000, '3') FROM dual
)
SELECT wm_concat(TO_CLOB(v))
  FROM t
;

by 미소애비 [2013.04.01 18:11:40]

저는 위 쿼리 잘 실행됩니다.
0.026초 걸리네요~
설마 버전 문제일까요?
참고로 제가 사용하는 시스템의 버전은 아래와 같습니다.

Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - 64bit Production
PL/SQL Release 11.2.0.2.0 - Production
"CORE 11.2.0.2.0 Production"
TNS for Linux: Version 11.2.0.2.0 - Production
NLSRTL Version 11.2.0.2.0 - Production

감사합니다~


by 마농 [2013.04.01 18:14:16]
음.. 제건 안되요.

Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production
PL/SQL Release 11.2.0.1.0 - Production
"CORE 11.2.0.1.0 Production"
TNS for 32-bit Windows: Version 11.2.0.1.0 - Production
NLSRTL Version 11.2.0.1.0 - Production

by 미소애비 [2013.04.01 18:14:41]
참고로,

서버가 여러대 있어서,
아래 서버에서 해보니까 에러 발생하네요~

ORA-06502: PL/SQL: 수치 또는 값 오류: 문자열 버퍼가 너무 작습니다
ORA-06512: "WMSYS.WM_CONCAT_IMPL", 줄 30에서
06502. 00000 -  "PL/SQL: numeric or value error%s"
*Cause:   
*Action:

아무래도 버전 문제가 아닐까 생각됩니다.

Oracle Database 11g Enterprise Edition Release 11.1.0.7.0 - 64bit Production
PL/SQL Release 11.1.0.7.0 - Production
"CORE 11.1.0.7.0 Production"
TNS for Linux: Version 11.1.0.7.0 - Production
NLSRTL Version 11.1.0.7.0 - Production

감사합니다~

by 마농 [2013.04.01 18:16:21]
CLOB 이 된다는건 대 환영입니다.
OVER 구문 없이 ListAgg 에서와 같은 정렬 기능만 좀 만들어 줬으면 하는 바램이네요.

by 손님 [2013.04.02 08:38:52]
WITH
TAB AS (
SELECT COD
   ,LPAD(COD + LVL,5) VAL
 FROM (
  SELECT 10000 COD FROM DUAL UNION ALL
  SELECT 20000 COD FROM DUAL UNION ALL
  SELECT 30000 COD FROM DUAL
  ) ,(
  SELECT LEVEL LVL
   FROM DUAL
   CONNECT BY LEVEL <= 5000
  )
)

-- 묶음 처리했습니다.
-- WM_CONCAT, LISTAGG 가 안되어서 XMLAGG 사용
-- (5:칼럼크기 + 1:구분자) * 5,000:최대ROW수 = 30,000:CONCAT한크기
-- 30,000 / 4,000:VARCHAR2크기 = 7.5 , 여유있게 10 묶음 처리
SELECT COD
   ,TO_CLOB(MAX(DECODE(NTL, 1 ,SUBSTR(VAL,2)))) ||
    TO_CLOB(MAX(DECODE(NTL, 2 ,VAL))) ||
    TO_CLOB(MAX(DECODE(NTL, 3 ,VAL))) ||
    TO_CLOB(MAX(DECODE(NTL, 4 ,VAL))) ||
    TO_CLOB(MAX(DECODE(NTL, 5 ,VAL))) ||
    TO_CLOB(MAX(DECODE(NTL, 6 ,VAL))) ||
    TO_CLOB(MAX(DECODE(NTL, 7 ,VAL))) ||
    TO_CLOB(MAX(DECODE(NTL, 8 ,VAL))) ||
    TO_CLOB(MAX(DECODE(NTL, 9 ,VAL))) ||
    TO_CLOB(MAX(DECODE(NTL,10 ,VAL))) VAL
 FROM ( 
  SELECT COD ,NTL
     ,SUBSTR(XMLAGG(XMLELEMENT(V ,',' ,VAL) ORDER BY VAL).EXTRACT('//text()') ,1) VAL
   FROM (
    SELECT COD ,VAL
       ,NTILE(10) OVER (PARTITION BY COD ORDER BY VAL) NTL
     FROM TAB
     ORDER BY COD ,VAL
    )
   GROUP BY COD ,NTL
  )
 GROUP BY COD

by 손님 [2013.04.03 08:13:09]
재밌는네요.

요즘은 그리드툴에서 거의 무한대의 피벗을 지원해준다고 하네요.
댓글등록
SQL문을 포맷에 맞게(깔끔하게) 등록하려면 code() 버튼을 클릭하여 작성 하시면 됩니다.
로그인 사용자만 댓글을 작성 할 수 있습니다. 로그인, 회원가입