PIVOT

PIVOT在行转列的时候经常用到,最便捷的方式就是通过示例来理解它的作用。

示例1 Query to Return Select Product Data from AdventureWorks

SELECT  PRODUCT.Name AS product_name ,
PRODUCT.Color AS product_color ,
PRODUCT_INVENTORY.LocationID ,
PRODUCT.ReorderPoint ,
PRODUCT_INVENTORY.Quantity AS product_quantity
FROM Production.Product PRODUCT
LEFT JOIN Production.ProductInventory PRODUCT_INVENTORY ON PRODUCT.ProductID = PRODUCT_INVENTORY.ProductID;

结果:

如果我们想要product_coor 在列里面显示每个产品的数量呢?这时候PIVOT就出场了

示例2:Common Use of PIVOT to Report on Products by Color

WITH    PRODUCT_DATA
AS ( SELECT PRODUCT.Name AS product_name ,
PRODUCT.Color AS product_color ,
PRODUCT.ReorderPoint ,
PRODUCT_INVENTORY.Quantity AS product_quantity
FROM Production.Product PRODUCT
LEFT JOIN Production.ProductInventory PRODUCT_INVENTORY ON PRODUCT.ProductID = PRODUCT_INVENTORY.ProductID
)
SELECT *
FROM PRODUCT_DATA PIVOT
( SUM(product_quantity) FOR product_color IN ( [Black], [Blue], [Grey],
[Multi], [Red], [Silver],
[Silver/Black], [White],
[Yellow] ) ) PIVOT_DATA;

结果:

从SQL中可以看出PIVOT有两个步骤

  • An aggregate function, which will aggregate if multiple values exist. In the initial
    SELECT statement that returns product data, there were many duplicate rows. This
    example uses SUM whenever this occurs, which will add up product quantities if there
    are multiple rows with the same product name.

  • A value list for all values that will be changed from row data into column headers. In
    this case, the list is of colors from Product.Color .

PS:虽然解决了行转列的问题,但这个时候,我们应该知道color里面到底有多少条唯一的数据,如果在我们不知的情况下,如何解决呢?这个时候动态SQL就来了。

示例3:Common Use of PIVOT to Report on Products by Color

USE AdventureWorks2014;
GO DECLARE @sql_command NVARCHAR(MAX);
DECLARE @sql_colors NVARCHAR(1000); SET @sql_command = '
WITH PRODUCT_DATA
AS ( SELECT PRODUCT.Name AS product_name ,
PRODUCT.Color AS product_color ,
PRODUCT.ReorderPoint ,
PRODUCT_INVENTORY.Quantity AS product_quantity
FROM Production.Product PRODUCT
LEFT JOIN Production.ProductInventory PRODUCT_INVENTORY ON PRODUCT.ProductID = PRODUCT_INVENTORY.ProductID
)
SELECT *
FROM PRODUCT_DATA PIVOT
( SUM(product_quantity) FOR product_color IN (';
WITH colorlist
AS ( SELECT DISTINCT
Product.Color AS color_name
FROM Production.Product
WHERE Product.Color IS NOT NULL
)
SELECT @sql_colors = ISNULL(@sql_colors, N'') + N','
+ QUOTENAME(color_name)
FROM colorlist; SET @sql_colors = STUFF(@sql_colors, 1, 1, ''); SET @sql_command = @sql_command + @sql_colors + N' )) PIVOT_DATA'; PRINT @sql_command;
EXEC sp_executesql @sql_command;

首先看一下打印出来的SQL:

WITH    PRODUCT_DATA
AS ( SELECT PRODUCT.Name AS product_name ,
PRODUCT.Color AS product_color ,
PRODUCT.ReorderPoint ,
PRODUCT_INVENTORY.Quantity AS product_quantity
FROM Production.Product PRODUCT
LEFT JOIN Production.ProductInventory PRODUCT_INVENTORY ON PRODUCT.ProductID = PRODUCT_INVENTORY.ProductID
)
SELECT *
FROM PRODUCT_DATA PIVOT
( SUM(product_quantity) FOR product_color IN ( [Black], [Blue], [Grey],
[Multi], [Red], [Silver],
[Silver/Black], [White],
[Yellow] ) ) PIVOT_DATA

结果:

从示例1到示例3,我们从中了解到如何把复杂的SQL慢慢分解出来,最后在组合在一起。

UNPIVOT

顾名思义,就是PIVOT的反向操作:列转行。我们还是从简单的示例到复杂的示例看慢慢了解。

PS:为了方便,就直接用上面的数据来做列转行。

示例1:Using UNPIVOT to Revert Column Headers into Row Data

WITH    PRODUCT_DATA
AS ( SELECT PRODUCT.Name AS product_name ,
PRODUCT.Color AS product_color ,
PRODUCT.ReorderPoint ,
PRODUCT_INVENTORY.Quantity AS product_quantity
FROM Production.Product PRODUCT
LEFT JOIN Production.ProductInventory PRODUCT_INVENTORY ON PRODUCT.ProductID = PRODUCT_INVENTORY.ProductID
),
PRODUCTS_BY_COLOR
AS ( SELECT *
FROM PRODUCT_DATA PIVOT
( SUM(product_quantity) FOR product_color IN ( [Black], [Blue], [Grey],
[Multi], [Red], [Silver],
[Silver/Black], [White],
[Yellow] ) ) PIVOT_DATA
)
SELECT *
FROM PRODUCTS_BY_COLOR UNPIVOT
( product_quantity FOR Color IN ( [Black], [Blue], [Grey], [Multi], [Red],
[Silver], [Silver/Black], [White], [Yellow] ) ) AS UNPIVOT_DATA;

从SQL中可以看出,UNPIVOT同样有两个步骤,这里就不详说了,可以查看MSND了解更多。

PS:我们必须指定列转行里面的字段,如果数据库增加了一个color,那我们必须要更改这段SQL,除非我们用动态SQL来实现。

示例2: A Dynamic UNPIVOT Using Original Row Data to Supply Color Names

USE AdventureWorks2014;
GO DECLARE @sql_command NVARCHAR(MAX);
DECLARE @sql_pivotcommand NVARCHAR(MAX);
DECLARE @sql_unpivotcommand NVARCHAR(MAX); DECLARE @sql_colors NVARCHAR(1000); SET @sql_pivotcommand = '
WITH PRODUCT_DATA
AS ( SELECT PRODUCT.Name AS product_name ,
PRODUCT.Color AS product_color ,
PRODUCT.ReorderPoint ,
PRODUCT_INVENTORY.Quantity AS product_quantity
FROM Production.Product PRODUCT
LEFT JOIN Production.ProductInventory PRODUCT_INVENTORY ON PRODUCT.ProductID = PRODUCT_INVENTORY.ProductID
),
PRODUCTS_BY_COLOR
AS ( SELECT *
FROM PRODUCT_DATA PIVOT ( SUM(product_quantity) FOR product_color IN (';
WITH colorlist
AS ( SELECT DISTINCT
Product.Color AS color_name
FROM Production.Product
WHERE Product.Color IS NOT NULL
)
SELECT @sql_colors = ISNULL(@sql_colors, N'') + N','
+ QUOTENAME(color_name)
FROM colorlist; SET @sql_colors = STUFF(@sql_colors, 1, 1, ''); SET @sql_pivotcommand = @sql_pivotcommand + @sql_colors + N' )) PIVOT_DATA)'; SET @sql_unpivotcommand = ' SELECT *
FROM PRODUCTS_BY_COLOR UNPIVOT ( product_quantity FOR Color IN (' + @sql_colors + ') ) AS UNPIVOT_DATA'; SET @sql_command = @sql_pivotcommand + @sql_unpivotcommand; PRINT @sql_command;
EXEC sp_executesql @sql_command;

打印出来的SQL:

WITH    PRODUCT_DATA
AS ( SELECT PRODUCT.Name AS product_name ,
PRODUCT.Color AS product_color ,
PRODUCT.ReorderPoint ,
PRODUCT_INVENTORY.Quantity AS product_quantity
FROM Production.Product PRODUCT
LEFT JOIN Production.ProductInventory PRODUCT_INVENTORY ON PRODUCT.ProductID = PRODUCT_INVENTORY.ProductID
),
PRODUCTS_BY_COLOR
AS ( SELECT *
FROM PRODUCT_DATA PIVOT
( SUM(product_quantity) FOR product_color IN ( [Black], [Blue], [Grey],
[Multi], [Red], [Silver],
[Silver/Black], [White],
[Yellow] ) ) PIVOT_DATA
)
SELECT *
FROM PRODUCTS_BY_COLOR UNPIVOT ( product_quantity FOR Color IN (
[Black], [Blue], [Grey],
[Multi], [Red], [Silver],
[Silver/Black], [White],
[Yellow] ) ) AS UNPIVOT_DATA

结果:

咦?这结果不是PIVOT示例1的么?怎么绕了一大圈又回到原地了?突然感觉神农百草结尾时说,这草有毒!

T-SQL Recipes之Dynamic PIVOT and UNPIVOT的更多相关文章

  1. 使用 PIVOT 和 UNPIVOT 行转列 列转行 报表统计 函数

    官方文档:http://technet.microsoft.com/zh-cn/library/ms177410(v=SQL.105).aspx 可以使用 PIVOT 和 UNPIVOT 关系运算符将 ...

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

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

  3. 通过sql做数据透视表,数据库表行列转换(pivot和Unpivot用法)(一)

    在mssql中大家都知道可以使用pivot来统计数据,实现像excel的透视表功能 一.MSsqlserver中我们通常的用法 1.Sqlserver数据库测试 ---创建测试表 Create tab ...

  4. Dynamic Pivot table wizard SQL Server

    原文 http://www.gyurcit.hu/pivot.html Dynamic Pivot table wizard This stored procedure generate dynami ...

  5. sql pivot、unpivot和partition by用法

    原文:sql pivot.unpivot和partition by用法 演示脚本 from sys.sysobjects where name = 'Student' AND type = 'U') ...

  6. sql 行转列 PIVOT 列转行 UNPIVOT

    原文:sql 行转列 PIVOT 列转行 UNPIVOT 一: 现有表一(t_table1),想转为表二(t_table2)的格式. 表一: 年 公司 收入 2013 公司1 12 2013 公司2 ...

  7. SQL行转列(PIVOT)与列转行(UNPIVOT)简明方法

    原文地址:https://www.cnblogs.com/linJie1930906722/p/6036714.html 在做数据统计的时候,行转列,列转行是经常碰到的问题.case when方式太麻 ...

  8. sql行列转换PIVOT与unPIVOT

    基本语法 select * from Mould pivot ( count(ID)for ProductTypeCode in ( [FC], [RCU], [RCD] )) as PVT; wit ...

  9. SQL Server 行列相互转换命令:PIVOT和UNPIVOT使用详解

    一.使用PIVOT和UNPIVOT命令的SQL Server版本要求 1.数据库的最低版本要求为SQL Server 2005 或更高. 2.必须将数据库的兼容级别设置为90 或更高. 3.查看我的数 ...

随机推荐

  1. 【新手出发】从搭虚拟机开始,一步一步在CentOS上跑起来.Net Core程序

    文章背景 微软6月26号发布core 1.0版本后,园子里关于这方面的文章就更加火爆了,不管是从文章数量还是大家互动的热情来看,绝对是最热门的技术NO.1.我从去年底开始接触.net core到现在也 ...

  2. pdfbox加载pdf时遇到wrappedioexception报错处理方式

    现在一个项目要对pdf做处理.由于其中一个pdf约为80M左右,用pdfbox读取pdf时遇到了wrappedioexception错误.监控得到说内存不足.于是请教项目经理.他告诉我在Open De ...

  3. 解决 release-stripped.ap_' specified for property 'resourceFile' does not exist.

    设置buildTypes里的release的shrinkResources为false即可,如果是 release-stripped.ap_' specified for property 'reso ...

  4. maven实战(02)_坐标详解

    (一)  何为mave坐标 maven的世界中拥有数量非常巨大的构件,也就是平时用的一些jar,war等文件. maven定义了这样一组规则: 世界上任何一个构件都可以使用Maven坐标唯一标志,ma ...

  5. 我的js函数库(持续更新)

    常用js初始化函数 function id(obj) { return document.getElementById(obj); } function bind(obj, ev, fn) { if ...

  6. docker 初探之简单安装 ----Windows10

    报错一 $ docker run hello-world Unable to find image 'hello-world:latest' locally Pulling repository do ...

  7. Node.js配合node-http-proxy解决本地开发ajax跨域问题

    情景: 前后端分离,本地前端开发调用接口会有跨域问题,一般有以下3种解决方法: 1. 后端接口打包到本地运行(缺点:每次后端更新都要去测试服下一个更新包,还要在本地搭建java运行环境,麻烦) 2. ...

  8. 通过rsync+inotify实现数据的实时备份

    我讲到过利用rsync实现数据的镜像和备份,但是要实现数据的实时备份,单独靠rsync还不能实现,本文就讲述下如何实现数据的实时备份. 一.rsync的优点与不足 与传统的cp.tar备份方式相比,r ...

  9. Python之mmap内存映射模块(大文本处理)说明

    背景: 通常在UNIX下面处理文本文件的方法是sed.awk等shell命令,对于处理大文件受CPU,IO等因素影响,对服务器也有一定的压力.关于sed的说明可以看了解sed的工作原理,本文将介绍通过 ...

  10. Socket通信功能实现

    前段时间写的小功能,包含了较为详细的代码注释,需要的可以下载看下.对你有一点用,请赞一个~~ http://www.cnblogs.com/zhili/category/397082.html  这里 ...