|
|
哇!真是八仙过海各显神通,我隆重宣布开发版进入鼎盛时期!
以下是我的几种方法,等会再和各位的对照一下:
VAR s VARCHAR2(200);
EXEC :s := 'A,B,C,D,E,F';
用BITAND的思路:
WITH t AS (
SELECT REGEXP_SUBSTR(:s,'[^,]+',1,ROWNUM) s,COUNT(*) OVER() cnt, ROWNUM rn
FROM DUAL
CONNECT BY ROWNUM<=LENGTH(:s)-LENGTH(REPLACE(:s,','))+1
)
, t2 AS (
SELECT ROWNUM id
FROM DUAL
CONNECT BY ROWNUM < POWER(2, (SELECT count(*) FROM t)) - 1
)
, bits AS (
SELECT id, BITAND(id, POWER(2, rn)) bit,s
FROM t, t2
)
SELECT id,WMSYS.WM_CONCAT(CASE WHEN bit=0 THEN s END),WMSYS.WM_CONCAT(CASE WHEN bit<>0 THEN s END)
FROM bits
GROUP BY id;
-----------------------------------------
假设全部元素都为单字符,用TRANSLATE求补集:
WITH t AS (
SELECT REGEXP_SUBSTR(:s,'[^,]+',1,ROWNUM) s,COUNT(*) OVER() cnt
FROM DUAL
CONNECT BY ROWNUM<=LENGTH(:s)-LENGTH(REPLACE(:s,','))+1
)
,t2 AS (
SELECT SYS_CONNECT_BY_PATH(s,',') s2
FROM t
CONNECT BY s>PRIOR s AND LEVEL<cnt
)
SELECT LTRIM(s2,',') AS COL1
,RTRIM(LTRIM(REGEXP_REPLACE(TRANSLATE(:s,s2,LPAD(',',LENGTH(s2),',')),'(,){2,}','\1'),','),',') AS COL2
FROM t2;
-----------------------
列转行,用分区外连接求补集,再用WM_CONCAT拼接:
WITH t AS (
SELECT REGEXP_SUBSTR(:s,'[^,]+',1,ROWNUM) s,COUNT(*) OVER() cnt
FROM DUAL
CONNECT BY ROWNUM<=LENGTH(:s)-LENGTH(REPLACE(:s,','))+1
)
,t2 AS (
SELECT ROWNUM AS id, SYS_CONNECT_BY_PATH(s,',') AS s2, LEVEL AS lvl
FROM t
CONNECT BY s>PRIOR s AND LEVEL<cnt
)
,t3 AS (
SELECT id
,REGEXP_SUBSTR(s2,'[^,]+',1,rn) S3
FROM t2
,(SELECT ROWNUM rn FROM DUAL CONNECT BY ROWNUM <=(SELECT MAX(cnt) FROM t))
WHERE t2.lvl>=rn
)
SELECT t3.id
,RTRIM(REGEXP_REPLACE(WMSYS.WM_CONCAT(s3),'(,){2,}','\1'),',')
,RTRIM(REGEXP_REPLACE(WMSYS.WM_CONCAT(CASE WHEN s3 IS NULL THEN s END),'(,){2,}','\1'),',')
FROM t3 PARTITION BY (id)
RIGHT JOIN t
ON t3.s3 = t.s
GROUP BY id;
-----------------------
同上,用xmlagg拼接:
WITH t AS (
SELECT REGEXP_SUBSTR(:s,'[^,]+',1,ROWNUM) s,COUNT(*) OVER() cnt
FROM DUAL
CONNECT BY ROWNUM<=LENGTH(:s)-LENGTH(REPLACE(:s,','))+1
)
,t2 AS (
SELECT ROWNUM AS id, SYS_CONNECT_BY_PATH(s,',') AS s2, LEVEL AS lvl
FROM t
CONNECT BY s>PRIOR s AND LEVEL<cnt
)
,t3 AS (
SELECT id
,REGEXP_SUBSTR(s2,'[^,]+',1,rn) S3
FROM t2
,(SELECT ROWNUM rn FROM DUAL CONNECT BY ROWNUM <=(SELECT MAX(cnt) FROM t))
WHERE t2.lvl>=rn
)
SELECT t3.id
,RTRIM(REGEXP_REPLACE(xmlagg(xmlelement (elmt,s3||',') order by s3).extract ('//text()'),'(,){2,}','\1'),',')
,RTRIM(REGEXP_REPLACE(xmlagg(xmlelement (elmt,(CASE WHEN s3 IS NULL THEN s END)||',') order by s).extract ('//text()'),'(,){2,}','\1'),',')
FROM t3 PARTITION BY (id)
RIGHT JOIN t
ON t3.s3 = t.s
GROUP BY id;
-----------------------
列转行,用MINUS求补集,用CONNECT BY拼接:
WITH t AS (
SELECT REGEXP_SUBSTR(:s,'[^,]+',1,ROWNUM) s,COUNT(*) OVER() cnt
FROM DUAL
CONNECT BY ROWNUM<=LENGTH(:s)-LENGTH(REPLACE(:s,','))+1
)
,t2 AS (
SELECT ROWNUM AS id, SUBSTR(SYS_CONNECT_BY_PATH(s,','),2) AS s2, LEVEL AS lvl
FROM t
CONNECT BY s>PRIOR s AND LEVEL<cnt
)
,t3 AS (
SELECT id
,REGEXP_SUBSTR(s2,'[^,]+',1,rn) S3
FROM t2
,(SELECT ROWNUM rn FROM DUAL CONNECT BY ROWNUM <=(SELECT MAX(cnt) FROM t))
WHERE t2.lvl>=rn
)
,t4 AS (
SELECT id,MAX(SUBSTR(SYS_CONNECT_BY_PATH(s,','),2)) AS s4
FROM (SELECT id,s,ROW_NUMBER() OVER(PARTITION BY id ORDER BY s) rn
FROM (SELECT t2.id,t.s
FROM t,t2
MINUS
select id,s3 from t3
)
)
START WITH rn=1 CONNECT BY id = PRIOR id AND rn=PRIOR rn+1
GROUP BY id
)
select s2,s4
FROM t2,t4
WHERE t2.id = t4.id; |
|