1. 程式人生 > >Oracle 行轉列pivot 、列轉行unpivot 的Sql語句總結

Oracle 行轉列pivot 、列轉行unpivot 的Sql語句總結

多行轉字串

這個比較簡單,用||concat函式可以實現

print?

1.  select concat(id,username) str from app_user  

2.    

3.  select id||username str from app_user  

字串轉多列

實際上就是拆分字串的問題,可以使用 substrinstrregexp_substr函式方式

字串轉多行

使用union all函式等方式

首先讓我們來看看這個神奇的函式wm_concat(列名),該函式可以把列值以","號分隔起來,並顯示成一行,接下來上例子,看看這個神奇的函式如何應用準備測試

資料

print?

1.  create table test(id number,name varchar2(20));  

2.    

3.  insert into test values(1,'a');  

4.  insert into test values(1,'b');  

5.  insert into test values(1,'c');  

6.  insert into test values(2,'d');  

7.  insert into test values(2,'e');  

效果1 :   行轉列預設逗號隔開

print?

1.  select

 wm_concat(namename from test;  

效果2:   把結果裡的逗號替換成"|"

print?

1.  select replace(wm_concat(name),',','|'from test;  

效果3:  ID分組合並name

print?

1.  select id,wm_concat(namename from test group by id;  

sql語句等同於下面的sql語句

print?

1.  -------- 適用範圍:8i,9i,10g及以後版本 MAX + DECODE   

2.  select

 id, max(decode(rn, 1, namenull)) || max(decode(rn, 2, ','||namenull)) || max(decode(rn, 3, ','||namenull)) str  

3.      from (select id, name ,row_number() over(partition by id order by nameas rn from test) t group by id order by 1;   

4.         

5.  -------- 適用範圍:8i,9i,10g及以後版本 ROW_NUMBER + LEAD   

6.  select id, str from (select id,row_number() over(partition by id order by nameas rn,name || lead(',' || name, 1)  

7.      over(partition by id order by name) ||  lead(',' || name, 2) over(partition by id order by name) || lead(',' || name, 3)   

8.      over(partition by id order by nameas str from test) where rn = 1 order by 1;  

9.      

10. -------- 適用範圍:10g及以後版本 MODEL   

11. select id, substr(str, 2) str from test model return updated rows partition by(id) dimension by(row_number()  

12.     over(partition by id order by nameas rn) measures (cast(name as varchar2(20)) as str) rules upsert iterate(3)  

13.     until(presentv(str[iteration_number + 2], 1, 0)=0) (str[0] = str[0] || ',' || str[iteration_number + 1]) order by 1;       

14.            

15. -------- 適用範圍:8i,9i,10g及以後版本 MAX + DECODE   

16. select t.id id, max(substr(sys_connect_by_path(t.name','), 2)) str from (select id, name, row_number()   

17.     over(partition by id order by name) rn from test) t start with rn = 1 connect by rn = prior rn + 1 and id = prior id  

18.     group by t.id;  

懶人擴充套件用法:

案例我要寫一個檢視,類似"create or replace view as select 欄位1,...欄位50 from tablename",基表有50多個欄位,要是靠手工寫太麻煩了,有沒有什麼簡便的方法? 當然有了,看我如果應用wm_concat來讓這個需求變簡單,假設我的APP_USER表中有(id,username,password,age4個欄位。查詢結果如下

print?

1.   /** 這裡的表名預設區分大小寫 */  

2.  select 'create or replace view as select '|| wm_concat(column_name) || ' from APP_USER' sqlStr   

3.         from user_tab_columns where table_name='APP_USER';    

利用系統表方式查詢

print?

1.  select * from user_tab_columns  

Oracle 11g中,Oracle 又增加了2個查詢:pivot(行轉列)unpivot(列轉行)

參考:http://blog.csdn.NET/tianlesoftware/article/details/7060306http://www.oracle.com/technetwork/cn/articles/11g-pivot-101924-zhs.html

pivot 列轉行

測試資料 (id,型別名稱,銷售數量),案例:根據水果的型別查詢出一條資料顯示出每種型別的銷售數量。

print?

1.  create table demo(id int,name varchar(20),nums int);  ---- 建立表  

2.  insert into demo values(1, '蘋果', 1000);  

3.  insert into demo values(2, '蘋果', 2000);  

4.  insert into demo values(3, '蘋果', 4000);  

5.  insert into demo values(4, '橘子', 5000);  

6.  insert into demo values(5, '橘子', 3000);  

7.  insert into demo values(6, '葡萄', 3500);  

8.  insert into demo values(7, '芒果', 4200);  

9.  insert into demo values(8, '芒果', 5500);  

分組查詢當然這是不符合查詢一條資料的要求的)

print?

1.  select namesum(nums) nums from demo group by name  

行轉列查詢

print?

1.  select * from (select name, nums from demo) pivot (sum(nums) for name in ('蘋果' 蘋果, '橘子''葡萄''芒果'));  

注意 pivot(聚合函式 for 列名 in(型別)),其中 in(‘’) 中可以指定別名,in中還可以指定子查詢,比如 select distinctcode from customers

當然也可以不使用pivot函式,等同於下列語句,只是程式碼比較長,容易理解

print?

1.  ------ 多項子查詢  

2.  select * from (select sum(nums) 蘋果 from demo where name='蘋果'),(select sum(nums) 橘子 from demo where name='橘子'),  

3.         (select sum(nums) 葡萄 from demo where name='葡萄'),(select sum(nums) 芒果 from demo where name='芒果');  

4.           

5.  ------  decode 函式利用  

6.  select sum(decode(name,'蘋果',nums)) 蘋果, sum(decode(name,'橘子',nums)) 橘子,   

7.         sum(decode(name,'葡萄',nums)) 葡萄, sum(decode(name,'芒果',nums)) 芒果 from demo  

unpivot 行轉列

顧名思義就是將多列轉換成1列中去案例:現在有一個水果表,記錄了4個季度的銷售數量,現在要將每種水果的每個季度的銷售情況用多行資料展示。

建立表和資料

print?

1.  create table Fruit(id int,name varchar(20), Q1 int, Q2 int, Q3 int, Q4 int);  

2.    

3.  insert into Fruit values(1,'蘋果',1000,2000,3300,5000);  

4.  insert into Fruit values(2,'橘子',3000,3000,3200,1500);  

5.  insert into Fruit values(3,'香蕉',2500,3500,2200,2500);  

6.  insert into Fruit values(4,'葡萄',1500,2500,1200,3500);  

7.  select * from Fruit  

列轉行查詢

print?

1.  select id , name, jidu, xiaoshou from Fruit unpivot (xiaoshou for jidu in (q1, q2, q3, q4) )  

注意:  unpivot沒有聚合函式,xiaoshoujidu欄位也是臨時的變數

同樣不使用unpivot也可以實現同樣的效果,只是sql語句會很長,而且執行速度效率也沒有前者高

print?

1.  select id, name ,'Q1' jidu, (select q1 from fruit where id=f.id) xiaoshou from Fruit f  

2.  union  

3.  select id, name ,'Q2' jidu, (select q2 from fruit where id=f.id) xiaoshou from Fruit f  

4.  union  

5.  select id, name ,'Q3' jidu, (select q3 from fruit where id=f.id) xiaoshou from Fruit f  

6.  union  

7.  select id, name ,'Q4' jidu, (select q4 from fruit where id=f.id) xiaoshou from Fruit f