pivot、unpivot實現oracle行列轉換

pwz1688發表於2015-07-16
11g之後,oracle增加了pivotunpivot語句,可以很方便的完成行列轉換。
先來看看pivot的語法是

點選(此處)摺疊或開啟

  1. SELECT ....
  2. FROM <table-expr>
  3.    PIVOT
  4.      (
  5.       aggregate-function(<column>)
  6.       FOR <pivot-column> IN (<value1>, <value2>,..., <valuen>)
  7.         ) AS <alias>
  8. WHERE .....
來看個例子,emp表中資料如下:

點選(此處)摺疊或開啟

  1. SQL> select empno,ename,job,sal,deptno from emp order by deptno,job;

  2.      EMPNO ENAME JOB SAL DEPTNO
  3. ---------- ---------- --------- ---------- ----------
  4.       7934 MILLER CLERK 1300 10
  5.       7782 CLARK MANAGER 2450 10
  6.       7839 KING PRESIDENT 5000 10
  7.       7902 FORD ANALYST 3000 20
  8.       7369 SMITH CLERK 800 20
  9.       7566 JONES MANAGER 2975 20
  10.       7900 JAMES CLERK 950 30
  11.       7698 BLAKE MANAGER 2850 30
  12.       7844 TURNER SALESMAN 1500 30
  13.       7521 WARD SALESMAN 1250 30
  14.       7499 ALLEN SALESMAN 1600 30

  15.      EMPNO ENAME JOB SAL DEPTNO
  16. ---------- ---------- --------- ---------- ----------
  17.       7654 MARTIN SALESMAN 1250 30

  18. 已選擇12行。
現在查詢各部門各工種的總薪水,如下:

點選(此處)摺疊或開啟

  1. SQL> select deptno,job,sum(sal) from emp group by deptno,job order by 1,2;

  2.     DEPTNO JOB SUM(SAL)
  3. ---------- --------- ----------
  4.         10 CLERK 1300
  5.         10 MANAGER 2450
  6.         10 PRESIDENT 5000
  7.         20 ANALYST 3000
  8.         20 CLERK 800
  9.         20 MANAGER 2975
  10.         30 CLERK 950
  11.         30 MANAGER 2850
  12.         30 SALESMAN 5600

  13. 已選擇9行。
現在需要將每個工種作為一列顯示就更一目瞭然,這就需要進行行列轉換了,先看11G之前,利用decode函式來實現行列轉換
 

點選(此處)摺疊或開啟

  1. SQL> edit
  2. 已寫入 file afiedt.buf

  3.   1 select deptno,
  4.   2 sum(decode(job,'CLERK',sal,0)) as CLERK_sal,
  5.   3 sum(decode(job,'MANAGER',sal,0)) as MANAGER_sal,
  6.   4 sum(decode(job,'PRESIDENT',sal,0)) as PRESIDENT_sal,
  7.   5 sum(decode(job,'ANALYST',sal,0)) as ANALYST_sal,
  8.   6 sum(decode(job,'SALESMAN',sal,0)) as SALESMAN_sal
  9.   7* from emp group by deptno order by 1
  10. SQL> /

  11.     DEPTNO CLERK_SAL MANAGER_SAL PRESIDENT_SAL ANALYST_SAL SALESMAN_SAL
  12. ---------- ---------- ----------- ------------- ----------- ------------
  13.         10 1300 2450 5000 0 0
  14.         20 800 2975 0 3000 0
  15.         30 950 2850 0 0 5600

  16. SQL>

再看看11G新特性pivot實現行列轉換,如下:

點選(此處)摺疊或開啟

  1. SQL> edit;
  2. 已寫入 file afiedt.buf

  3.   1 select * from(
  4.   2 select deptno,job,sal from emp
  5.   3 )
  6.   4 pivot(
  7.   5 sum(sal) for job in(
  8.   6 'PRESIDENT' as PRESIDENT_SAL,
  9.   7 'MANAGER' as MANAGER_SAL,
  10.   8 'ANALYST' as ANALYST_SAL,
  11.   9 'CLERK' as CLERK_SAL,
  12.  10 'SALESMAN' as SALESMAN_SAL
  13.  11 )
  14.  12* ) order by 1
  15. SQL> /

  16.     DEPTNO PRESIDENT_SAL MANAGER_SAL ANALYST_SAL CLERK_SAL SALESMAN_SAL
  17. ---------- ------------- ----------- ----------- ---------- ------------
  18.         10 5000 2450 1300
  19.         20 2975 3000 800
  20.         30 2850 950 5600

  21. SQL>

實際上,oracle對pivot子句中出現的列以外的列做了一個隱式的group by.現在,如果想要再結果中增加1列,顯示部門的薪水總合,可以這麼做

點選(此處)摺疊或開啟

  1. SQL> edit
  2. 已寫入 file afiedt.buf

  3.   1 select * from(
  4.   2 select deptno,job,sal,sum(sal) over(partition by deptno) sal_total from emp
  5.   3 )
  6.   4 pivot(
  7.   5 sum(sal) as total_sal for job in(
  8.   6 'PRESIDENT' as P,
  9.   7 'MANAGER' as M,
  10.   8 'ANALYST' as A,
  11.   9 'CLERK' as C,
  12.  10 'SALESMAN' as S
  13.  11 )
  14.  12* ) order by 1
  15. SQL> /

  16.     DEPTNO SAL_TOTAL P_TOTAL_SAL M_TOTAL_SAL A_TOTAL_SAL C_TOTAL_SAL S_TOTAL_SAL
  17. ---------- ---------- ----------- ----------- ----------- ----------- -----------
  18.         10 8750 5000 2450 1300
  19.         20 6775 2975 3000 800
  20.         30 9400 2850 950 5600

  21. SQL>
說明:
1)oracle對pivot子句中出現的列以外的列,也就是deptno和SAL_TOTAL做了隱式的group by.這裡用了分析函式,對於每個deptno,SAL_TOTAL是唯一的,所以group by的結果還是3行。
2)oracle會拼接列名 = for字句中別名+聚合函式別名,比如'P'+'_'+'SAL_TOTAL'
可以指定多個聚合函式,如統計薪水總合與人數總合,如下:

點選(此處)摺疊或開啟

  1. SQL> edit;
  2. 已寫入 file afiedt.buf

  3.   1 select * from(
  4.   2 select deptno,job,sal from emp
  5.   3 )
  6.   4 pivot(
  7.   5 sum(sal) as sal_total,count(sal) as emp_total for job in(
  8.   6 'PRESIDENT' as PRESIDENT,
  9.   7 'MANAGER' as MANAGER
  10.   8 )
  11.   9* ) order by 1
  12. SQL> /

  13.     DEPTNO PRESIDENT_SAL_TOTAL PRESIDENT_EMP_TOTAL MANAGER_SAL_TOTAL MANAGER_EMP_TOTAL
  14. ---------- ------------------- ------------------- ----------------- -----------------
  15.         10 5000 1 2450 1
  16.         20 0 2975 1
  17.         30 0 2850 1

for子句可以指定多列,如想統計salesman和clerk員工,其mgr為7902和7698各自的人數,如下:

點選(此處)摺疊或開啟

  1. SQL> edit;
  2. 已寫入 file afiedt.buf

  3.   1 select * from(
  4.   2 select deptno,job,mgr from emp
  5.   3 )
  6.   4 pivot(
  7.   5 count(mgr) as emp_total for(job,mgr) in(
  8.   6 ('SALESMAN', '7902') as SALESMAN_7902,
  9.   7 ('SALESMAN', '7698') as SALESMAN_7698,
  10.   8 ('CLERK', '7902') as CLERK_7902,
  11.   9 ('CLERK', '7698') as CLERK_7698
  12.  10 )
  13.  11* )
  14. SQL> /

  15.     DEPTNO SALESMAN_7902_EMP_TOTAL SALESMAN_7698_EMP_TOTAL CLERK_7902_EMP_TOTAL CLERK_7698_EMP_TOTAL

  16. ---------- ----------------------- ----------------------- -------------------- --------------------

  17.         30 0 4 0 1

  18.         20 0 0 1 0

  19.         10 0 0 0 0

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/21251711/viewspace-1734828/,如需轉載,請註明出處,否則將追究法律責任。

相關文章