使用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_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
 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM