如何把用逗號等字符隔開的字符串轉換成列表,下面依逗號分隔符為例:
比如有一個字符串,其值為:香港,張家港,北京,上海
用SQL把這個字符串轉換成列表的方法是:
1、方法一
WITH A AS (SELECT '香港,張家港,北京,上海' A FROM DUAL) SELECT DECODE(B,0,SUBSTR(A,C),SUBSTR(A,C,B-C)) city FROM ( SELECT A,B,(LAG(B,1,0) OVER(ORDER BY LV))+1 C FROM( SELECT A,INSTR(A,',',1,LEVEL) B,LEVEL LV FROM A CONNECT BY LEVEL <=(LENGTH(A) - LENGTH(REPLACE(A,',','')))+1 ) )
輸出結果是:
香港
張家港
北京
上海
應用舉例:
如果table1表的city字段的值為:北京;table2表的city字段的值為:香港,張家港,北京,上海
要想用city字段關聯table1,table2表來查詢table1表中的數據,首先我們會想到用(例:select * from table1 where field in (select field from table2))方式來查詢,但是這樣查詢的結果卻不正確,仔細觀察會發現如果用in時,table2表的city字段的值必須得是('香港','張家港','北京','上海')格式,這樣查詢的結果才會正確,這時如果我們使用下面的SQL就可幫我們解決這個問題了。
例:select * from table where field in ( WITH A AS (SELECT (select field from table2) A FROM DUAL) SELECT DECODE(B,0,SUBSTR(A,C),SUBSTR(A,C,B-C)) city FROM (SELECT A,B,(LAG(B,1,0) OVER(ORDER BY LV))+1 C FROM(SELECT A,INSTR(A,',',1,LEVEL) B,LEVEL LV FROM A CONNECT BY LEVEL <=(LENGTH(A) - LENGTH(REPLACE(A,',','')))+1 )))
2、方法二:使用Oracle regexp_substr中的正則表達式
WITH temp AS (SELECT '香港,張家港,北京,上海,95,aa' text FROM DUAL) SELECT regexp_substr (text, '[^,]+', 1, rn) city FROM temp t1, (SELECT LEVEL rn FROM DUAL CONNECT BY LEVEL <= (SELECT LENGTH (text) - LENGTH (REPLACE (text, ',', '')) + 1 FROM temp)) t2
3、方法三:使用的表(FW_ANSWER)
select answer from fw_answer ANSWER ----------------- A,B,C A,F B,D,E D
要把逗號分隔的轉列換成行顯示,這里使用了substr的方式,如下:
select substr(answer,instr(','||answer|| ',', ',', 1, t2.row_num), instr(','||answer|| ',', ',', 1, t2.row_num+1)-1-instr(','||answer, ',', 1, t2.row_num)) answer from fw_answer t1,(select rownum row_num from user_objects where rownum<= 10) t2 where nvl(substr(answer,instr(','||answer||',', ',', 1, t2.row_num), instr(','||answer||',', ',', 1, t2.row_num+1)-1-instr(','||answer, ',', 1, t2.row_num)),'-')!='-' order by answer
查詢結果:
ANSWER ----------------- A A B B C D D E F
【如果是使用其他字符分隔的,以上方式也可以,只需要將有逗號的地方換成該字符。】
以上方式是針對字符存儲無規律的情況,對於fw_answer表中的答案列是有規律可循的,所以簡化后的sql如下:
select substr(answer,t2.row_num*2-1,1) answer from fw_answer t1,(select rownum row_num from user_objects where rownum<= 10) t2 where nvl(substr(answer,t2.row_num*2-1,1),'-')!='-' order by answer
【注:user_objects主要描述當前用戶通過DDL建立的所有對象。包括表、視圖、索引、存儲過程、觸發器、
包、索引、序列等。是oracle字典表的視圖。這里也可以通過其它方式,如dual,此處為了免去content by
所以不用dual,用user_objects。】
------------------------------------------------------------------------------------------------------
正好相反的操作:把列轉換成行
從網上找了都是關於decode的方法實現的列轉行,后來發現了用orcale的wmsys.wm_concat方法可以輕松的實現,下面的范例是網上找的:wmsys.wm_concat要10g以后才可以。
表結構: 1 A 1 B 1 C 2 A 2 B 3 C 3 F 4 D 轉換后變成: 1 A,B,C 2 A,B 3 C,F 4 D
方法:
假設你的表結構是tb_name(id, remark),則語句如下:
SELECT a.id, wm_concat (a.remark) new_result FROM tb_name a group by a.id