1. 程式人生 > >使用SQL如何把用逗號等字元隔開的字串轉換成列表

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