在Oracle中,如果要实现行列转换,较为常见的是用DECODE和CASE语句。对于简单的行列转行,DECODE和CASE语句尚能应付。在逻辑比较复杂,分组聚合较多的场景中,DECODE和CASE语句则力有不逮。而pivot则可完美解决这一切。

首先,我们来看看Oracle对于其的解释:

可见,pivot是数据仓库中的关键技术,它利用交叉查询(crosstabulation query)将行转换为列。

基本语法如下:

SELECT ....
FROM <table-expr>
PIVOT
(
aggregate-function(<column>)
FOR <pivot-column> IN (<value1>, <value2>,..., <valuen>)
) AS <alias>
WHERE .....

下面我们来通过具体的案例对其进行阐述。

首先,构造案例所需的数据,

1> 创建视图,以EMP表的数据作为源数据。

CREATE VIEW emp_view AS
SELECT
deptno,job,to_char(hiredate,'yyyy') hiredate,
count(*) cnt,sum(sal) sum_sal
FROM emp
GROUP BY deptno,job,to_char(hiredate,'yyyy');

其中,deptno为部门号,job为工作的类型(即工种),hiredate为雇佣的日期,cnt为特定部门,特定工种在特定年份雇佣的员工的总数,sum_sal为特定部门,特定工种,特定年份雇佣的员工的工资的总和。

2> 视图的数据如下:

SQL> select * from emp_view;

    DEPTNO JOB       HIRE        CNT    SUM_SAL
---------- --------- ---- ---------- ----------
20 CLERK 1980 1 800
20 ANALYST 1981 1 3000
20 ANALYST 1987 1 3000
30 CLERK 1981 1 950
30 MANAGER 1981 1 2850
10 MANAGER 1981 1 2450
30 SALESMAN 1981 4 5600
20 MANAGER 1981 1 2975
10 PRESIDENT 1981 1 5000
10 CLERK 1982 1 1300
20 CLERK 1987 1 1100 11 rows selected.

应用场景一:

基本的Pivot转换

例1:

SELECT * FROM
( SELECT deptno,hiredate,cnt
FROM emp_view
) PIVOT (SUM(cnt)
FOR hiredate IN ('' AS "1980",'' AS "1981",
'' AS "1982",'' AS "1987"))
ORDER BY deptno; DEPTNO 1980 1981 1982 1987
---------- ---------- ---------- ---------- ----------
10 2 1
20 1 2 2
30 6 3 rows selected.

例2:

SELECT * FROM
( SELECT deptno,job,cnt
FROM emp_view
) PIVOT (SUM(cnt)
FOR job IN ('CLERK','ANALYST','MANAGER','SALESMAN','PRESIDENT'))
ORDER BY deptno; DEPTNO 'CLERK' 'ANALYST' 'MANAGER' 'SALESMAN' 'PRESIDENT'
---------- ---------- ---------- ---------- ---------- -----------
10 1 1 1
20 2 2 1
30 1 1 4 3 rows selected.

两例以不同的列进行统计,前者是hiredate,后者是job。

除此之外,前者用了别名,后面没有用别名,两者的显示效果也是不一样的。

应用场景二:

对多列进行Pivot转换

SELECT * FROM
( SELECT deptno,job,hiredate,cnt
FROM emp_view
) PIVOT (SUM(cnt)
FOR (job,hiredate) IN
(('CLERK','') AS clerk_1980,
('CLERK','') AS clerk_1981,
('ANALYST','') AS analyst_1987,
('MANAGER','') AS manager_1981
)
)
ORDER by deptno; DEPTNO CLERK_1980 CLERK_1981 ANALYST_1987 MANAGER_1981
---------- ---------- ---------- ------------ ------------
10 1
20 1 1 1
30 1 1 3 rows selected.

限于篇幅,FOR (job,hiredate) IN语句中没有列出更多组合,只列出了四组,当然,我们可以根据实际场景需要罗列更多的组合。

从本例中可以看出,对两个列进行Pivot转换可从三个维度呈现统计结果。

应用场景三:

用Pivot实现多个聚合

SELECT * FROM
( SELECT deptno,hiredate,cnt,sum_sal
FROM emp_view
) PIVOT ( SUM(cnt) AS cnt,
SUM(sum_sal) AS sum_sal
FOR hiredate IN ('','','',''))
ORDER BY deptno; DEPTNO ''_CNT ''_SUM_SAL ''_CNT ''_SUM_SAL ''_CNT ''_SUM_SAL ''_CNT ''_SUM_SAL
---------- ---------- -------------- ---------- -------------- ---------- -------------- ---------- --------------
10 2 7450 1 1300
20 1 800 2 5975 2 4100
30 6 9400 3 rows selected.

'1981'_CNT指的是1981年雇佣的员工的总数,'1981'_SUM_SAL指的是1981年雇佣员工所开出的工资。

具体到本例中,即1981年10号部门招聘了2位员工,开出的工资合计为7450元,20号部门招聘了2位员工,开出的工资合计为5975元,30号部门招聘了6名员工,开出的工资合计为9400元,依次类推。

既然有pivot将行转换为列,同样也有unpivot操作将聚合后的列转换为行。

UNPIVOT

以上述应用场景三的结果作为源数据进行操作

CREATE TABLE T1 AS
SELECT * FROM
( SELECT deptno,hiredate,cnt,sum_sal
FROM emp_view
) PIVOT ( SUM(cnt) AS cnt,
SUM(sum_sal) AS sum_sal
FOR hiredate IN ('' AS "1980",'' AS "1981",
'' AS "1982",'' AS "1987"))
ORDER BY deptno

表T1的结果为:

SQL> select * from t1;

    DEPTNO   1980_CNT 1980_SUM_SAL   1981_CNT 1981_SUM_SAL   1982_CNT 1982_SUM_SAL   1987_CNT 1987_SUM_SAL
---------- ---------- ------------ ---------- ------------ ---------- ------------ ---------- ------------
10 2 7450 1 1300
20 1 800 2 5975 2 4100
30 6 9400 3 rows selected.

首先进行一维unpivot

SELECT deptno,DECODE(hiredate,'1980_CNT','','1981_CNT','','1982_CNT','','1987_CNT','') AS hiredate,cnt
FROM T1
UNPIVOT INCLUDE NULLS
( cnt
FOR hiredate IN ("1980_CNT","1981_CNT","1982_CNT","1987_CNT")); DEPTNO HIRE CNT
---------- ---- ----------
10 1980
10 1981 2
10 1982 1
10 1987
20 1980 1
20 1981 2
20 1982
20 1987 2
30 1980
30 1981 6
30 1982
30 1987 12 rows selected.

输出的结果为不同部门在不同年份的雇佣人数,

注意:上述SQL语句中UNPIVOT后加了INCLUDE NULLS,当然也可以指定为EXCLUDE NULLS,即排除cnt为空的值,如果不指定,则默认为EXCLUDE NULLS。

UNPIVOT后不指定INCLUDE NULLS的输入结果为:

    DEPTNO HIRE        CNT
---------- ---- ----------
10 1981 2
10 1982 1
20 1980 1
20 1981 2
20 1987 2
30 1981 6 6 rows selected.

下面,我们再进行二维unpivot

SELECT deptno,hiredate,cnt,sum_sal
FROM T1
UNPIVOT
( (cnt,sum_sal)
FOR hiredate IN (("1980_CNT","1980_SUM_SAL") AS 1980,
("1981_CNT","1981_SUM_SAL") AS 1981,
("1982_CNT","1982_SUM_SAL") AS 1982,
("1987_CNT","1987_SUM_SAL") AS 1987)); DEPTNO HIREDATE CNT SUM_SAL
---------- ---------- ---------- ----------
10 1981 2 7450
10 1982 1 1300
20 1980 1 800
20 1981 2 5975
20 1987 2 4100
30 1981 6 9400 6 rows selected.

输入结果为T1表列转行的结果。

参考文档:

SQL for Analysis and Reporting

如何用Pivot实现行列转换的更多相关文章

  1. SQL pivot 基本用法 行列转换 数据透视

    SQL通过pivot进行行列转换 数据透视 可直接在sql server 运行 传统操作 和 pivot create table XKCl (name nchar(10) not null, 学科 ...

  2. KingbaseES 行列转换函数

    关键字:    行专列,列转行, pivot, unpivot 行列转换是在数据分析中经常用到的一项功能,KingbaseES从V8R6C3B0071版本开始通过扩展插件(kdb_utils_func ...

  3. SQL Server中行列转换 Pivot UnPivot

    SQL Server中行列转换 Pivot UnPivot PIVOT用于将列值旋转为列名(即行转列),在SQL Server 2000可以用聚合函数配合CASE语句实现 PIVOT的一般语法是:PI ...

  4. SQL(横表和纵表)行列转换,PIVOT与UNPIVOT的区别和使用方法举例,合并列的例子

    使用过SQL Server 2000的人都知道,要想实现行列转换,必须综合利用聚合函数和动态SQL,具体实现起来需要一定的技巧,而在SQL Server 2005中,使用新引进的关键字PIVOT/UN ...

  5. SQL Server SQL性能优化之--pivot行列转换减少扫描计数优化查询语句

    原文出处:http://www.cnblogs.com/wy123/p/5933734.html 先看常用的一种表结构设计方式: 那么可能会遇到一种典型的查询方式,主子表关联,查询子表中的某些(或者全 ...

  6. SQL中PIVOT 行列转换

    来源:http://www.studyofnet.com/news/295.html PIVOT通过将表达式某一列中的唯一值转换为输出中的多个列来旋转表值表达式,并在必要时对最终输出中所需的任何其余列 ...

  7. 每日学习心得:SQL查询表的行列转换/小计/统计(with rollup,with cube,pivot解析)

    2013-8-20 1.    SQL查询表的行列转换/小计/统计(with  rollup,with cube,pivot解析) 在实际的项目开发中有很多项目都会有报表模块,今天就通过一个小的SQL ...

  8. 行列转换小结 Pivot ,Unpivot (转,改)

    行专列 Pivot 1)SQL 2000版本 静态 SELECT ID , SUM(CASE Code WHEN 'Item1' THEN Value END) AS Item1 , SUM(CASE ...

  9. SQL查询表的行列转换/小计/统计(with rollup,with cube,pivot解析)

    SQL查询表的行列转换/小计/统计(with rollup,with cube,pivot解析) 2013-8-20 1.    SQL查询表的行列转换/小计/统计(with  rollup,with ...

随机推荐

  1. sphinx搜索实例

    多个关键词搜索一个字段的几种方式测试 @proname "ygm" "磨粉机" "2" //搜索结果proname字段必须同时包含3个词,有 ...

  2. common.js js中常用方法

    //创建CSS样式段 //classid: CSS样式段ID//font: 字体//size: 字体大小//color: 字体颜色//style: 字体风格function FCMakeCSSClas ...

  3. HTML5将图片转化成字符画

    HTML5将图片转化成字符画 字符画大家一定非常熟悉了,那么如何把一张现有的图片转成字符画呢?HTML5让这个可能变成了现实,通过canvas,可以很轻松实现这个功能.其实原理很简单:扫描图片相应位置 ...

  4. homework-02

    关于输入 先来说说关于输入的事情.其实我最一开始并没有发现输入数字之间是用逗号隔开的,所以我是当做空格隔开来写的,后来发现以后匆忙改正,利用strtok与atoi函数从字符串中提取出用逗号隔开的数字. ...

  5. JS中常遇到的浏览器兼容问题和解决方法

    今天整理了一下浏览器对JS的兼容问题,希望能给你们带来帮助,我没想到的地方请留言给我,我再加上: 常遇到的关于浏览器的宽高问题: //以下均可console.log()实验 var winW=docu ...

  6. 如何解决Maple的应用在数学中

    对任意数学和技术学科的研究员.教师和学生而言,Maple是一个必备的工具.通过Maple,教师将复杂数学问题注入生命,学生的精力集中在概念理解上而不是如何使用工具上,研究员可以开发更复杂的算法或模型. ...

  7. 使用 MimeKit 和 MailKit 发送邮件

    MimeKit 给.NET 社区带来了一流的 MIME 解析器,它能处理复杂的各种Mime, 性能好.而且开箱即用支持 S/MIME 和 PGP.MimeKit 和 MailKit 支持最新的国际化的 ...

  8. 思维导图FreeMind

    什么是MindMap? MindMap(被译成思维导图或心智图)是一种思维工具,由英国的记忆之父托尼-博赞发明. MindMap是一种新的思维模式,它将左脑的逻辑.顺序.条例.文字.数字,以及右脑的图 ...

  9. Logging with NLog

    相比较log4net, 我更喜欢NLog, 因为NLog 更简单, 而且配置选项也更加的清楚,可能是因为log4net 是从log4j 移植过来的一个原因吧,总感觉有很多的java 成分在. 要使用N ...

  10. Box-sizing:小身材,大拳头!

    国庆回来,很久没写博客了.一来是自己毫无时间,二是最近开发任务特别紧,三是节后综合症,脑子一片空白没有找到写作的原材料.今天,在加完班回来的22点,忙里偷闲,分享一下最近学到的一个小知识点如题.标题的 ...