oracle 轉置實現


下面是3種方法 
方法1:SYS_CONNECT_BY_PATH , ROW_NUMBER() OVER(PARTITION BY  ..  ORDER BY ..)  , START WITH , CONNECT BY PRIOR 組合使用 
方法2:wmsys.wm_concat 
方法3:listagg(oracle 11g release 2) 用法就像聚合函數一樣,通過Group by語句,把每個Group的一個字段,拼接起來. 

listagg 語法概述


   listagg函數的語法結構如下:
LISTAGG( [,]) WITHIN GROUP (ORDER BY ) [OVER (PARTITION BY )]

    listagg雖然是聚合函數,但可以提供分析功能(比如可選的OVER()子句)。使用listagg中,下列中的元素是必須的:

  • 需要聚合的列或者表達式
  • WITH GROUP 關鍵詞
  • 分組中的ORDER BY子句

   下面將演示listagg函數使用的例子


 

例: 
table1 中 1個col1對應多個col2,下面我們需要把col2轉置如col2字段值為 



需要變為 2-3-4 這樣的格式,並且col2值是不可枚舉的有上千或上萬種,這樣其他有些通過decode方式的轉置就不能實現 

使用方法1

 1 SELECT TT.col1,
 2        '-' || ':' ||
 3        TO_CHAR(SUBSTR(MAX(SYS_CONNECT_BY_PATH(TT.col2, '-')), 2)) M 
 4        --這里是為了截取掉 SYS_CONNECT_BY_PATH 在第一個值前加的"-"
 5   FROM (SELECT T.col1,
 6                T.col2,
 7                T.col1 + ROW_NUMBER() OVER(PARTITION BY T.col1 ORDER BY T.col2) RN,
 8                ROW_NUMBER() OVER(PARTITION BY T.col1 ORDER BY T.col2) RM
 9         --上面2行用了2次 ROW_NUMBER() 是因為 col1是累加的值所以一個 T.col1 + ROW_NUMBER() 是為了區別不同的分組,ROW_NUMBER() 這個是為了設置遞歸的起始值,但對於不同的分組都會有這個值"1"所以需要使用2個
10           FROM table1 T
11          WHERE /*T.col1 = TO_NUMBER('1013010875782363')*/) TT  --注釋的部分是我測試用的
12  START WITH RM = 1
13 CONNECT BY PRIOR RN + 1 = RN
14  GROUP BY TT.col1 ;

方法2

select substr(tt.co, 1, length(tt.co) - 1), --去結尾"-"
       tt.col1
  from (select t.col1, replace(wmsys.wm_concat(t.col2 || '-'), ',', null) co --去掉","
          from table1 t
        --WHERE T.col1 = TO_NUMBER('1013010875782363')
         group by t.col1) tt;

方法3

select population,  
       nation,  
       city,  
       listagg(city,',') within GROUP (order by city) over (partition by nation) rank  
from temp 

或者

select nation,listagg(city,',') within GROUP (order by city)  
from temp  
group by nation 

 

第二個雖然簡單但是

wmsys.wm_concat對象實現行列轉換的方法,這種方法不被Oracle所推薦,因為WMSYS用戶用於Workspace Manager,其函數對象可能因版本而不同,這種變化在11.2.0.3及10.2.0.5中體現出來。原本WM_CONCAT函數返回值為VARCHAR2變更為CLOB。這一變化導致了很多程序的異常。 
參考 
http://www.eygle.com/archives/2012/10/wmsys_wm_concat.html

 

 -------20150522 update--------

轉置實現
說明:把 TF_B_TRADE_SP 里一個訂單的SP增加或減少的 SP_PRODUCT_ID 轉置后以一條行記錄的形式列出

 1 SELECT TT.TRADE_ID,
 2        '-' || ',' ||
 3        SUBSTR(MAX(SYS_CONNECT_BY_PATH(TT.SP_PRODUCT_ID, '-')), 2)
 4   FROM (SELECT T.TRADE_ID,
 5                T.SP_PRODUCT_ID,
 6                T.MODIFY_TAG,
 7                T.TRADE_ID + ROW_NUMBER() OVER(PARTITION BY T.TRADE_ID ORDER BY T.SP_PRODUCT_ID) RN,
 8                ROW_NUMBER() OVER(PARTITION BY T.TRADE_ID ORDER BY T.SP_PRODUCT_ID) RM
 9           FROM TF_B_TRADE_SP T
10          WHERE T.TRADE_ID = TO_NUMBER(:VTRADE_ID)
11            AND T.MODIFY_TAG IN ('1', 'B')) TT
12  START WITH RM = 1
13 CONNECT BY PRIOR RN + 1 = RN
14  GROUP BY TT.TRADE_ID
15 UNION ALL
16 SELECT TT.TRADE_ID,
17        '+' || ',' ||
18        SUBSTR(MAX(SYS_CONNECT_BY_PATH(TT.SP_PRODUCT_ID, '-')), 2)
19   FROM (SELECT T.TRADE_ID,
20                T.SP_PRODUCT_ID,
21                T.MODIFY_TAG,
22                T.TRADE_ID + ROW_NUMBER() OVER(PARTITION BY T.TRADE_ID ORDER BY T.SP_PRODUCT_ID) RN,
23                ROW_NUMBER() OVER(PARTITION BY T.TRADE_ID ORDER BY T.SP_PRODUCT_ID) RM
24           FROM TF_B_TRADE_SP T
25          WHERE T.TRADE_ID = TO_NUMBER(:VTRADE_ID)
26            AND T.MODIFY_TAG IN ('0', 'A')) TT
27  START WITH RM = 1
28 CONNECT BY PRIOR RN + 1 = RN
29  GROUP BY TT.TRADE_ID;
View Code

 

修改后最后寫好是這樣

 1 SELECT MI.M || ',' || AD.A
 2   FROM (SELECT TT.TRADE_ID,
 3                '-' || ':' ||
 4                TO_CHAR(SUBSTR(MAX(SYS_CONNECT_BY_PATH(TT.SP_PRODUCT_ID, '_')),
 5                               2)) M
 6           FROM (SELECT T.TRADE_ID,
 7                        T.SP_PRODUCT_ID,
 8                        T.MODIFY_TAG,
 9                        T.TRADE_ID + ROW_NUMBER() OVER(PARTITION BY T.TRADE_ID ORDER BY T.SP_PRODUCT_ID) RN,
10                        ROW_NUMBER() OVER(PARTITION BY T.TRADE_ID ORDER BY T.SP_PRODUCT_ID) RM
11                   FROM TF_B_TRADE_SP T
12                  WHERE T.TRADE_ID = TO_NUMBER('1013010875782363')
13                    AND T.MODIFY_TAG IN ('1', 'B')) TT
14          START WITH RM = 1
15         CONNECT BY PRIOR RN + 1 = RN
16          GROUP BY TT.TRADE_ID) MI,
17        (SELECT TT.TRADE_ID,
18                '+' || ':' ||
19                TO_CHAR(SUBSTR(MAX(SYS_CONNECT_BY_PATH(TT.SP_PRODUCT_ID, '_')),
20                               2)) A
21           FROM (SELECT T.TRADE_ID,
22                        T.SP_PRODUCT_ID,
23                        T.MODIFY_TAG,
24                        T.TRADE_ID + ROW_NUMBER() OVER(PARTITION BY T.TRADE_ID ORDER BY T.SP_PRODUCT_ID) RN,
25                        ROW_NUMBER() OVER(PARTITION BY T.TRADE_ID ORDER BY T.SP_PRODUCT_ID) RM
26                   FROM TF_B_TRADE_SP T
27                  WHERE T.TRADE_ID = TO_NUMBER('1013010875782363')
28                    AND T.MODIFY_TAG IN ('0', 'A')) TT
29          START WITH RM = 1
30         CONNECT BY PRIOR RN + 1 = RN
31          GROUP BY TT.TRADE_ID) AD;
View Code

 

說明

 1 SELECT TT.col1,
 2        '-' || ':' ||
 3        TO_CHAR(SUBSTR(MAX(SYS_CONNECT_BY_PATH(TT.col2, '-')), 2)) M 
 4        --這里是為了截取掉 SYS_CONNECT_BY_PATH 在第一個值前加的"-"
 5   FROM (SELECT T.col1,
 6                T.col2,
 7                T.col1 + ROW_NUMBER() OVER(PARTITION BY T.col1 ORDER BY T.col2) RN,
 8                ROW_NUMBER() OVER(PARTITION BY T.col1 ORDER BY T.col2) RM
 9         --上面2行用了2次 ROW_NUMBER() 是因為 col1是累加的值所以一個 T.col1 + ROW_NUMBER() 是為了區別不同的分組,ROW_NUMBER() 這個是為了設置遞歸的起始值,但對於不同的分組都會有這個值"1"所以需要使用2個
10           FROM table1 T
11          WHERE /*T.col1 = TO_NUMBER('1013010875782363')*/) TT  --注釋的部分是我測試用的
12  START WITH RM = 1
13 CONNECT BY PRIOR RN + 1 = RN
14  GROUP BY TT.col1 ;
View Code

 

 

 


免責聲明!

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



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