SQL 使用SQL Server的PIVOT操作符创建交叉报表

SQL 使用SQL Server的PIVOT操作符创建交叉报表,你想创建一个交叉报表,以实现把行形式的结果集转换为列形式。你已经掌握了传统的做法,但这次希望尝试一些不同的技巧。尤其是你希望不使用 CASE 表达式或连接操作就能返回如下所示的结果集。

SQL 使用SQL Server的PIVOT操作符创建交叉报表 问题描述

你想创建一个交叉报表,以实现把行形式的结果集转换为列形式。你已经掌握了传统的做法,但这次希望尝试一些不同的技巧。尤其是你希望不使用 CASE 表达式或连接操作就能返回如下所示的结果集。

DEPT_10    DEPT_20    DEPT_30    DEPT_40
------- ---------- ---------- ----------
      3          5          6          0

SQL 使用SQL Server的PIVOT操作符创建交叉报表 解决方案

使用 PIVOT 操作符生成要求的结果集,而不使用 CASE 表达式或额外的连接操作。

1  select [10] as dept_10,
2         [20] as dept_20,
3         [30] as dept_30,
4         [40] as dept_40
5    from (select deptno, empno from emp) driver
6   pivot (
7      count(driver.empno)
8      for driver.deptno in ( [10],[20],[30],[40] )
9   ) as empPivot

SQL 使用SQL Server的PIVOT操作符创建交叉报表 扩展知识

最初看到 PIVOT 操作符可能会觉得陌生,其实在上述解决方案中,它执行的操作在技术上等价于我们所熟知的形式变换查询,如下所示。

select sum(case deptno when 10 then 1 else 0 end) as dept_10,
       sum(case deptno when 20 then 1 else 0 end) as dept_20,
       sum(case deptno when 30 then 1 else 0 end) as dept_30,
       sum(case deptno when 40 then 1 else 0 end) as dept_40
  from emp
 
DEPT_10    DEPT_20    DEPT_30    DEPT_40
------- ---------- ---------- ----------
      3          5          6          0

在对 PIVOT 操作有了基本的了解后,现在我们把它拆解开来,看看它究竟做了些什么。上述解决方案中的第 5 行展示了内嵌视图 DRIVER

from (select deptno, empno from emp) driver

我选择使用别名 driver,是因为该内嵌视图[即“表表达式”(table expression)]中的数据会直接流入 PIVOT 操作。PIVOT 操作符通过评估第 8 行的 FOR 列表中的项目把行转换为列,如下所示。

for driver.deptno in ( [10],[20],[30],[40] )

执行过程大致如下。
(1) 如果 DEPTNO 等于 10,就针对相关的行执行预先定义好的聚合操作(COUNT(DRIVER.EMPNO))。
(2) 针对 DEPTNO 等于 20、30 和 40 的行重复同样的操作。
第 8 行方括号里的项目不仅能够为聚合操作提供值,同时,这些项目也变成了结果集里的列名(不带方括号)。上述解决方案的 SELECT 子句也引用了 FOR 列表里的那些项目,并为它们分别指定了别名。如果不为 FOR 列表里的项目指定别名,则那些项目就会变成列名,但是会去掉方括号。
还有一个非常有趣之处,由于 DRIVER 只是一个普通的内嵌视图,因此可以使用更复杂的 SQL。假设我们希望修改结果集,把实际的部门名称作为结果集的列名。下面列出了 DEPT 表的数据。

select * from dept
 
DEPTNO DNAME          LOC
------ -------------- -------------
    10 ACCOUNTING     NEW YORK
    20 RESEARCH       DALLAS
    30 SALES          CHICAGO
    40 OPERATIONS     BOSTON

我们希望借助 PIVOT 返回如下所示的结果集。

ACCOUNTING   RESEARCH      SALES OPERATIONS
---------- ---------- ---------- ----------
          3         5          6          0

内嵌视图 DRIVER 事实上能够接受任何有效的表表达式,因此可以先把 EMP 表和 DEPT 表连接起来,然后使用 PIVOT 逐一评估其查询结果。下面的查询将返回上述要求的结果集。

select [ACCOUNTING] as ACCOUNTING,
       [SALES]      as SALES,
       [RESEARCH]   as RESEARCH,
       [OPERATIONS] as OPERATIONS
  from (
          select d.dname, e.empno
            from emp e,dept d
           where e.deptno=d.deptno
 
        ) driver
 pivot (
  count(driver.empno)
  for driver.dname in ([ACCOUNTING],[SALES],[RESEARCH],[OPERATIONS])
 ) as empPivot

如上所述,PIVOT 提供了一种有趣的转换结果集的办法。如果你以前习惯使用传统的转换方法,现在不妨将其作为另一种选择放入你的工具箱。

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程