zoukankan      html  css  js  c++  java
  • Oracle利用PIVOT和UNPIVOT进行行列转换

    在数据库开发中,我们会经常遇到行转列和列转行的情况,方法很多,比如使用CASE...WHEN...、DECODE,或者PIVOT和UNPIVOT都可以实现该功能,本篇讲解下PIVOT和UNPIVOT的使用,希望可以让读者举一反三,了解行列转换的用法。

    PIVOT语法

    SELECT ...
       FROM ...
       PIVOT [XML] 
                ( pivot_clause 
                   pivot_for_clause 
                   pivot_in_clause )
    WHERE ...
    说明:
    pivot_clause:定义将要进行聚合操作的列;
    pivot_for_clause:定义将要进行分组和转换的列;
    pivot_in_clause:定义在pivot_for_clause中对列的过滤,对于pivot_in_clause中每一个值进行,并转换为单个列。

    pivot_clause::=



    pivot_for_clause::=



    pivot_in_clause::=


    演示(利用Oracle的样例数据库,Schema为SCOTT):
    1、首先我们产生一些基本数据,用于演示的基础;
    SQL> select job,deptno ,sum(sal) as sum_sal 
      2    from emp
      3   group by job,deptno
      4   order by job,deptno;
    
    JOB	      DEPTNO	SUM_SAL
    --------- ---------- ----------
    ANALYST 	  20	   6000
    CLERK		  10	   1300
    CLERK		  20	   1900
    CLERK		  30	    950
    MANAGER 	  10	   2450
    MANAGER 	  20	   2975
    MANAGER 	  30	   2850
    PRESIDENT	  10	   5000
    SALESMAN	  30	   6100
    
    9 rows selected.
    2、使用WITH..as利用PIVOT对DEPTNO进行转列;
    SQL> with pivot_emp as(
      2       select job,deptno,sal from emp)
      3  select *
      4    from pivot_emp
      5   pivot(
      6         sum(sal) 
      7          for deptno 
                  in(10 as dept_10,20 as dept_20,30 as dept_30,40 as dept_40)
      8        );
    
    JOB	     DEPT_10	DEPT_20    DEPT_30    DEPT_40
    --------- ---------- ---------- ---------- ----------
    CLERK		1300	   1900        950
    SALESMAN			      6100
    PRESIDENT	5000
    MANAGER 	2450	   2975       2850
    ANALYST 		   6000
    3、也可以使用内联视图利用PIVOT对DEPTNO进行转列,和上面的结果相同;
    SQL> select *from (select sal,deptno,job from emp)
      2  pivot (
      3  sum(sal)
      4  for deptno in(10,20,30,40)
      5  );
    
    JOB		  10	     20 	30	   40
    --------- ---------- ---------- ---------- ----------
    CLERK		1300	   1900        950
    SALESMAN			      6100
    PRESIDENT	5000
    MANAGER 	2450	   2975       2850
    ANALYST 		   6000
    
    SQL> 
    4、查询整个表,对DEPTNO进行转换;
    SQL> select *from emp
      2  pivot(
      3  sum(sal) for deptno in (10,20,30,40)
      4  );
    结果省略...
    5、PIVOT查询对于别名的使用;
    SQL> select *
      2    from (select job , deptno , sal from emp)
      3    pivot(
      4         sum(sal) as sum_sal
      5         for deptno 
      6          in (10 as dept_10 , 20 , 30 , 40 as dept_40)
      7         );
    
    JOB	  DEPT_10_SUM_SAL 20_SUM_SAL 30_SUM_SAL DEPT_40_SUM_SAL
    --------- --------------- ---------- ---------- ---------------
    CLERK		     1300	1900	    950
    SALESMAN				   6100
    PRESIDENT	     5000
    MANAGER 	     2450	2975	   2850
    ANALYST 			6000
    说明:pivot_clause中的聚合函数,如果设置了别名,会和pivot_in_clause中的列名或别名进行拼接,如果不设置,则只显示pivot_in_clause中的列名或别名。
    6、PIVOT多行查询;
    SQL> select *
      2     from (select job , deptno , sal from emp)
      3      pivot(
      4          sum(sal) as sum_sal,
      5          count(sal) as cnt
      6          for deptno
      7           in (10 as dept_10, 20 ,30 ,40)
      8            );
    JOB	  DEPT_10_SUM_SAL DEPT_10_CNT 20_SUM_SAL     20_CNT 30_SUM_SAL	   30_CNT 40_SUM_SAL	 40_CNT
    --------- --------------- ----------- ---------- ---------- ---------- ---------- ---------- ----------
    CLERK		     1300	    1	    1900	  2	   950		1		      0
    SALESMAN			    0			  0	  6100		4		      0
    PRESIDENT	     5000	    1			  0			0		      0
    MANAGER 	     2450	    1	    2975	  1	  2850		1		      0
    ANALYST 			    0	    6000	  2			0		      0
    7、for in含有多列的查询;
    SQL> select *
      2    from (select job ,deptno, sal from emp)
      3    pivot(
      4         sum(sal) as sum_sal,count(1) as cnt
      5         for (deptno,job) 
      6          in(
      7             (30,'MANAGER') as d30_mgr,
      8             (30,'CLERK') as d30_clerk,
      9             (30,'SALESMAN') as d30_salman
     10             )
     11           );
    
    D30_MGR_SUM_SAL D30_MGR_CNT D30_CLERK_SUM_SAL D30_CLERK_CNT D30_SALMAN_SUM_SAL D30_SALMAN_CNT
    --------------- ----------- ----------------- ------------- ------------------ --------------
    	   2850 	  1		  950		  1		  6100		    4
    8、知道列的命名规则,可以在Select字段中列出要查询的列;
    SQL> select d30_mgr_sum_sal, d30_mgr_cnt
      2    from (select job ,deptno, sal from emp)
      3    pivot(
      4          sum(sal) as sum_sal,count(1) as cnt
      5           for (deptno,job) 
      6           in(
      7              (30,'MANAGER') as d30_mgr,
      8              (30,'CLERK') as d30_clerk,
      9              (30,'SALESMAN') as d30_salman
     10             )
     11           );
    
    D30_MGR_SUM_SAL D30_MGR_CNT
    --------------- -----------
    	   2850 	  1
    9、查看用PIVOT进行转换的执行计划,其实也对CASE...WHEN的改写而已;
    SCOTT@orcl _SQL>explain plan set statement_id='pivot'
      2  for
      3  select *
      4    from (select job,deptno,sal from emp)
      5   pivot(
      6        sum(sal)
      7        for deptno 
      8         in (10 as dept_10,20 as dept_20,30 as dept_30,40 as dept_40)
      9       );
    
    Explained.
    SCOTT@orcl _SQL>select *from table(dbms_xplan.display(null,'pivot','TYPICAL +PROJECTION'));
    
    PLAN_TABLE_OUTPUT
    --------------------------------------------------------------------------------
    Plan hash value: 1475541029
    
    ----------------------------------------------------------------------------
    | Id  | Operation	    | Name | Rows  | Bytes | Cost (%CPU)| Time	   |
    ----------------------------------------------------------------------------
    |   0 | SELECT STATEMENT    |	   |	 5 |	75 |	 4  (25)| 00:00:01 |
    |   1 |  HASH GROUP BY PIVOT|	   |	 5 |	75 |	 4  (25)| 00:00:01 |
    |   2 |   TABLE ACCESS FULL | EMP  |	14 |   210 |	 3   (0)| 00:00:01 |
    ----------------------------------------------------------------------------
    
    Column Projection Information (identified by operation id):
    
    PLAN_TABLE_OUTPUT
    --------------------------------------------------------------------------------
    -----------------------------------------------------------
    
       1 - (#keys=1) "JOB"[VARCHAR2,9], SUM(CASE  WHEN ("DEPTNO"=10) THEN
           "SAL" END )[22], SUM(CASE  WHEN ("DEPTNO"=20) THEN "SAL" END )[22],
           SUM(CASE  WHEN ("DEPTNO"=30) THEN "SAL" END )[22], SUM(CASE  WHEN
           ("DEPTNO"=40) THEN "SAL" END )[22]
       2 - "JOB"[VARCHAR2,9], "SAL"[NUMBER,22], "DEPTNO"[NUMBER,22]
    
    18 rows selected.

    UNPIVOT语法

    SELECT ...
       FROM ...
    UNPIVOT [INCLUDE|EXCLUDE NULLS] 
           ( unpivot_clause 
             unpivot_for_clause 
             unpivot_in_clause )
    WHERE ...

    unpivot_clause::=



    unpivot_in_clause::=


    演示:
    1、创建一个view,用于存放基础数据;
    SCOTT@orcl _SQL>create view pivoted_emp as
      2    select *
      3      from (select job,deptno,sal from emp)
      4      pivot (
      5              sum(sal)
      6              for deptno 
      7              in (10 as dept10,20 as dept20,30 as dept30,40 as dept40)
      8             );
    
    SCOTT@orcl _SQL>select *from pivoted_emp;
    
    JOB	      DEPT10	 DEPT20     DEPT30     DEPT40
    --------- ---------- ---------- ---------- ----------
    CLERK		1300	   1900        950
    SALESMAN			      6100
    PRESIDENT	5000
    MANAGER 	2450	   2975       2850
    ANALYST 		   6000
    
    SCOTT@orcl _SQL>
    2、利用UNPIVOT进行列转行操作;
    SCOTT@orcl _SQL>select *
      2  from pivoted_emp
      3  unpivot (
      4  sal 
      5  for deptno in (dept10 as 10,dept20 as 20,dept30 as 30, dept40 as 40)
      6  );
    
    JOB	      DEPTNO	    SAL
    --------- ---------- ----------
    CLERK		  10	   1300
    CLERK		  20	   1900
    CLERK		  30	    950
    SALESMAN	  30	   6100
    PRESIDENT	  10	   5000
    MANAGER 	  10	   2450
    MANAGER 	  20	   2975
    MANAGER 	  30	   2850
    ANALYST 	  20	   6000
    
    9 rows selected.
    
    SCOTT@orcl _SQL>
    3、从上面的结果显示,不包含NULL值的JOB,如果显示出来,需要使用INCLUDE关键字;
    SCOTT@orcl _SQL>select *
      2    from pivoted_emp
      3    unpivot include nulls(
      4    sal
      5    for deptno in (dept10 as 10,dept20 as 20,dept30 as 30, dept40 as 40)
      6  );
    
    JOB	      DEPTNO	    SAL
    --------- ---------- ----------
    CLERK		  10	   1300
    CLERK		  20	   1900
    CLERK		  30	    950
    CLERK		  40
    SALESMAN	  10
    SALESMAN	  20
    SALESMAN	  30	   6100
    SALESMAN	  40
    PRESIDENT	  10	   5000
    PRESIDENT	  20
    PRESIDENT	  30
    
    JOB	      DEPTNO	    SAL
    --------- ---------- ----------
    PRESIDENT	  40
    MANAGER 	  10	   2450
    MANAGER 	  20	   2975
    MANAGER 	  30	   2850
    MANAGER 	  40
    ANALYST 	  10
    ANALYST 	  20	   6000
    ANALYST 	  30
    ANALYST 	  40


  • 相关阅读:
    测试思想-测试方法 常用测试操作手段
    测试思想-测试执行 缺陷提交,优先级
    loadrunner 技巧-模拟Run Logic中的随机Action运行
    loadrunner 脚本开发-执行操作系统命令
    测试思想-测试执行 测试过程中的用例维护
    测试思想-测试执行 如何进行回归测试?
    python 全栈开发,Day62(外键的变种(三种关系),数据的增删改,单表查询,多表查询)
    python 全栈开发,Day61(库的操作,表的操作,数据类型,数据类型(2),完整性约束)
    python 全栈开发,Day60(MySQL的前戏,数据库概述,MySQL安装和基本管理,初识MySQL语句)
    python 全栈开发,Day59(小米商城)
  • 原文地址:https://www.cnblogs.com/alen-liu-sz/p/12975726.html
Copyright © 2011-2022 走看看