ITPub博客

首页 > 数据库 > Oracle > pivot、unpivot实现oracle行列转换

pivot、unpivot实现oracle行列转换

原创 Oracle 作者:pwz1688 时间:2015-07-16 10:34:03 0 删除 编辑
11g之后,oracle增加了pivot和unpivot语句,可以很方便的完成行列转换。
先来看看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博客 ” ,链接:https://blog.itpub.net/21251711/viewspace-1734828/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2009-03-30

  • 博文量
    106
  • 访问量
    736027