行轉列的一個SQL寫法(以Oracle爲例)

在數據分析的過程當中,經常會遇到行轉列的問題。例如,系統按事務逐條擺放,可是分析時但願以某個線索(例如每個客戶)爲中心,查看全部的事項。寫個性化程序或者寫自定義聚合函數均可以有很好的解決方案,可是計算環境複雜多變,有程序未必能部署上,掌握一個SQL寫法快速響應大多數分析場景仍是頗有必要的。本文以Oracle爲例,主要使用了row_number函數(不使用rank函數的緣由是不但願出現2條記錄排名相同的狀況,咱們的最終目的是行轉列,不是合理排名)sql

下列sql準備一下測試數據:數據庫

  
  
  
  
  1. -- drop table example_row_data;  
  2.  
  3. create table example_row_data (  
  4.        user_school varchar2(2000),  
  5.        user_name varchar2(2000),  
  6.        user_item varchar2(2000),  
  7.        user_value number         
  8. );  
  9.  
  10. insert into example_row_data(user_school,user_name,user_item,user_value) values('博客','iData_1','Linux',20);  
  11. insert into example_row_data(user_school,user_name,user_item,user_value) values('博客','iData_1','BI',2);  
  12. insert into example_row_data(user_school,user_name,user_item,user_value) values('博客','iData_1','數據庫',20);  
  13. commit;  
  14. insert into example_row_data(user_school,user_name,user_item,user_value) values('博客','iData_2','Linux',10);  
  15. insert into example_row_data(user_school,user_name,user_item,user_value) values('博客','iData_2','BI',30);  
  16. commit;  
  17. insert into example_row_data(user_school,user_name,user_item,user_value) values('博客','iData_3','Linux',5);  
  18. insert into example_row_data(user_school,user_name,user_item,user_value) values('博客','iData_3','BI',2);  
  19. insert into example_row_data(user_school,user_name,user_item,user_value) values('博客','iData_3','數據庫',6);  
  20. insert into example_row_data(user_school,user_name,user_item,user_value) values('博客','iData_3','數據挖掘',20);  
  21. commit

 查看樣例數據:ide

  
  
  
  
  1. SQL> select substr(t.user_school,1,4) 類別,substr(user_name,1,8) 用戶 ,substr(t.user_item,1,8) 科目,substr(t.user_value,1,2) 數值 from example_row_data t;  
  2.    
  3. 類別     用戶             科目             數值  
  4. -------- ---------------- ---------------- ----  
  5. 博客     iData_1          Linux            20  
  6. 博客     iData_1          BI               2  
  7. 博客     iData_1          數據庫           20  
  8. 博客     iData_2          Linux            10  
  9. 博客     iData_2          BI               30  
  10. 博客     iData_3          Linux            5  
  11. 博客     iData_3          BI               2  
  12. 博客     iData_3          數據庫           6  
  13. 博客     iData_3          數據挖掘         20  
  14.    
  15. rows selected 

行轉列前的準備工做,計算單個用戶最大可能的科目數:函數

  
  
  
  
  1. SQL> SELECT MAX(cnt)  
  2.   2  FROM   (SELECT t.user_school  
  3.   3                ,t.user_name  
  4.   4                ,COUNT(*) cnt  
  5.   5          FROM   example_row_data t  
  6.   6          GROUP  BY t.user_school  
  7.   7                   ,t.user_name) t;  
  8.    
  9.   MAX(CNT)  
  10. ----------  
  11.          4 

行轉列(已知最大科目數爲4):測試

  
  
  
  
  1. SELECT substr(t.user_school, 1, 4) 類別  
  2.       ,substr(t.user_name, 1, 8) 用戶  
  3.       ,MAX(decode(rk, 1, rpad(t.user_item || ':' || t.user_value, 14, ' '), NULL)) ||  
  4.        MAX(decode(rk, 2, rpad(t.user_item || ':' || t.user_value, 14, ' '), NULL)) ||  
  5.        MAX(decode(rk, 3, rpad(t.user_item || ':' || t.user_value, 14, ' '), NULL)) ||  
  6.        MAX(decode(rk, 4, rpad(t.user_item || ':' || t.user_value, 14, ' '), NULL)) 科目成績  
  7. FROM   (SELECT t.*  
  8.               ,row_number() over(PARTITION BY t.user_school, t.user_name ORDER BY t.user_item) rk  
  9.         FROM   example_row_data t) t  
  10. GROUP  BY t.user_school  
  11.          ,t.user_name;  
  12.  
  13. 類別     用戶             科目成績  
  14. -------- ---------------- ---------------------------------------------------  
  15. 博客     iData_1          BI:2          Linux:20      數據庫:20  
  16. 博客     iData_2          BI:30         Linux:10  
  17. 博客     iData_3          BI:2          Linux:5       數據庫:6      數據挖掘:20 
相關文章
相關標籤/搜索