sql中把字符串例如(‘香港,張家港,北京,上海’)分割成(‘香港’,‘張家港’,‘北京’,‘上海’)

如何把用逗號等字符隔開的字符串轉換成列表,下面依逗號分隔符爲例:

比如有一個字符串,其值爲:香港,張家港,北京,上海
用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_num2-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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章