SQL点滴19—T-SQL中的透视和逆透视

简介:    透视 今天抽一点时间来看看透视和逆透视语句,简单的说就是行列转换。假设一个销售表中存放着产品号,产品折扣,产品价格三个列,每一种产品号可能有多种折扣,每一种折扣只对应一个产品价格。下面贴出建表语句和插入数据语句。

   

透视

今天抽一点时间来看看透视和逆透视语句,简单的说就是行列转换。假设一个销售表中存放着产品号,产品折扣,产品价格三个列,每一种产品号可能有多种折扣,每一种折扣只对应一个产品价格。下面贴出建表语句和插入数据语句。

 
 
1 create table SalesOrderDetail(
2 ProductID int /* unique多谢wuu00的提醒*/ ,
3 UnitPriceDiscount float ,
4 ProductPrice float
5 )
6   insert into SalesOrderDetail values
7 ( 711 ,. 00 , 12 ),
8 ( 711 ,. 00 , 13 ),
9 ( 711 ,. 02 , 17 ),
10 ( 711 ,. 02 , 16 ),
11 ( 711 ,. 05 , 19 ),
12 ( 711 ,. 05 , 20 ),
13 ( 711 ,. 10 , 21 ),
14 ( 711 ,. 10 , 22 ),
15 ( 711 ,. 15 , 23 ),
16 ( 711 ,. 15 , 24 ),
17 ( 747 ,. 00 , 41 ),
18 ( 747 ,. 00 , 42 ),
19 ( 747 ,. 02 , 45 ),
20 ( 747 ,. 02 , 46 ),
21 ( 776 ,. 20 , 50 ),
22 ( 776 ,. 20 , 49 ),
23 ( 776 ,. 35 , 52 ),
24 ( 776 ,. 35 , 53 )

首先来看一条查询语句

 
 
1 select ProductID,UnitPriceDiscount, SUM (ProductPrice) as SumPrice
2   from SalesOrderDetail
3   group by ProductID,UnitPriceDiscount
4 order by ProductID,UnitPriceDiscount

这条语句查询每一种产品针对每一种折扣的价钱总和,查询结果如下图1

img_92d3a657ed4fca8d65d8268f2f75b1f3.png

图1

  

从图中我们可以看出771号产品有4种折扣,747号产品有2种折扣,776号产品有2种折扣。现在如果我们想知道每一种产品折扣,每一种产品的销售总价是多少,如下图2

img_ca197797edc19c1c68ce339df9f9a213.png

图2

  

如图对于折扣0,产品711的总价是25,对以折扣0.02,产品711的总价是33等等不再列举。原来的行是产品号,现在产品号变成了列,原来的折扣变成了现在的第一列。这就是数据透视的效果。下面我们开看看是这个效果是如何用语句实现的。

 
 
1 select * from
2 ( select sod.ProductPrice,sod.ProductID,sod.UnitPriceDiscount from SalesOrderDetail sod) so
3 pivot
4 (
5 sum (so.ProductPrice) for so.ProductID in ( [ 711 ] , [ 747 ] , [ 776 ] )
6 ) as pt
7 order by UnitPriceDiscount

  

首选创建子查询(select sod.ProductPrice,sod.ProductID,sod.UnitPriceDiscount from SalesOrderDetail sod) so ,透视运算符要使用这个子查询中的数据进行聚合运算,此外输出显示也要用到子查询中的列。代码生成一个别名为so的表值表达式。在这个表中使用pivot在特定的列上进行聚合,这里是对so.ProductPrice进行聚合,聚合针对so.ProductID进行。在这个例子中对三种产品的中的每一种创建一个列。这个相当于group by,从so表达式中进行数据筛选。不过这里没有选出ProductPrice,仅仅生成每行三个列,每一种产品为一个列的结果集。因此带有povit的表值表达式生成一个临时的结果集,将这个结果集命名为pt,使用这个结果集生成我们需要的输出。如果想要得到一个更加合适的列名可以修改筛选条件。如下:

 
 
1 select pt.UnitPriceDiscount, [ 711 ] as Product711, [ 747 ] as Product747, [ 776 ] as Product747 from
2 ( select sod.ProductPrice,sod.ProductID,sod.UnitPriceDiscount from SalesOrderDetail sod) so
3 pivot
4 (
5 sum (so.ProductPrice) for so.ProductID in ( [ 711 ] , [ 747 ] , [ 776 ] )
6 ) as pt
7 order by UnitPriceDiscount

  

输出的结果如下图3

img_ca197797edc19c1c68ce339df9f9a213.png

图3

  

逆透视

这次我们首先看语句和查询结果再分析,语句如下:

  

 
 
1 select ProductID,UnitPriceDiscount,ProductPrice
2 from
3 ( select UnitPriceDiscount,Product711,Product747,Product776 from #Temp1) as up1
4 unpivot(ProductPrice for ProductID in (Product711,Product747,Product776)) as up2
5 order by ProductID

查询结果如下图4:

img_f75d465ca369f0b44a4bd7a3d2705e9a.png

图4



首先我们来看看逆透视得到了一个什么样的结果。对于每一种产品的每一种折扣查询得到他们的合计售价,这个和上面图1中的结果是一样的,是的,它和透视之前的结果是相同的。逆透视和透视并不是完全相反。Pivot会执行聚合,把可能存在的多个行合并输出得到一行。由于已经进行了合并,unpivot无法重新生成原始的表值表达式,unpivot输入中的null值将在输出中消失,尽管在pivot操作之前输入中可能存在原始的null值。如图5是他们的比较。在图中我们可以看到NULL值下面一个图中没有NULL值,刚好有9行。下图把他们放在一起比较。

 

img_8f8886fb2c3ada6ddd4999f67cb2195d.png

图5

下面我们来剖析一下上面的语句到底做了些什么。首先是一个表值函数(select UnitPriceDiscount,Product711,Product747,Product776 from #Temp1) as up1,这个表值函数从透视结果,也就是临时表中,然后针对每一个产品号进行逆透视:unpivot(ProductPrice for ProductID in(Product711,Product747,Product776)) as up2,然后从逆透视结果中选择ProductID ,ProductPrice,从表值函数中选择UnitPriceDiscount。

延伸阅读

一个例子还不足以让我们理解这个语句,下面来看看TechNet中的例子。

SELECT DaysToManufacture, AVG(StandardCost) AS AverageCost FROM Production.Product

GROUP BY DaysToManufacture;

这个语句查出Product表中的制造时间和平均成本,得到如下的结果

img_c9388b0a9f3057b5f2037bfbfe801218.png

图6

如图可以看到没有制造时间为3天的产品,这里留下一个伏笔,在透视之后会出现一个NULL值。下面使用透视语句对它进行行列转换,就是使用0,1,2,3来作为列,使用具体的制造成本作为行数据。语句如下

 

 
 
1 select
2 'AverageCost' as Cost_Sorted_By_Production_Days,
3 [0],[1],[3],[4]
4 from
5 (select DaysToManufacture,StandardCost from Production.Product) as SourceTable
6 pivot
7 (avg(StandardCost) for DaysToManufacture in ([0],[1],[3],[4])) as PivotTable

依旧,首先用一个表值表达式把要透视的列和透视的项选择出来,然后使用透视语句针对每一个项计算平均成本,最后从这个透视结果中选择出结果。
结果如下图7,我们可以看到制造时间为3天的产品没有一个对应的平均成本。
img_175a06e0b95cc46d2d560d1f45e8d1ae.png

图7

 

下面这个例子稍微复杂一点。

 
 
1 SELECT VendorID,count(PurchaseOrderID) as PurchaseCunt
2 FROM Purchasing.PurchaseOrderHeader group by VendorID

这条语句查询得到每个供应商和他对应的交易号的个数,也就是每个供应商成交的交易次数。如图8列举出部分结果

img_cdd780e83b47f4581c2ff9612aaad303.png

图8

从图中我们可以看到供应商1共成交51比交易,供应商2共成交51笔交易。如果我们想查出这些交易分别是和那些雇员成交的应该怎么写呢?首先我们来看看表中全部的雇员情况。

select distinct(EmployeeID) from Purchasing.PurchaseOrderHeader

查询结果如图9

img_a20de276dc075c7afdfcc9b8427904c8.png

图9

如上图我们可以看到共有12个雇员有成交记录。对于这些雇员,如下查询语句

 

 
 
1 SELECT
2 VendorID,
3 [164] AS Emp164,
4 [198] AS Emp198,
5 [223] AS Emp223,
6 [231] AS Emp231,
7 [233] AS Emp233,
8 [238] as Emp238,
9 [241] as Emp241,
10 [244] as Emp244,
11 [261] as Emp261,
12 [264] as Emp264,
13 [266] as Emp266,
14 [274] as Emp274
15 FROM
16 (SELECT PurchaseOrderID,EmployeeID,VendorID
17 FROM Purchasing.PurchaseOrderHeader) p
18 PIVOT
19 (
20 COUNT (PurchaseOrderID)
21 FOR EmployeeID IN
22 ( [164], [198], [223], [231],[233],[238],[241],[244],[261],[264],[266],[274])
23 ) AS pvt
24 ORDER BY pvt.VendorID;

查询结果如下图10

img_d3a47aa7249239d42b6af052738f6050.png

图10

可以 简单地计算一下1+4+3+5+4+4+4+5+5+4+5+6+2刚好等于51,分开来看就是1号供应商分别和164号雇员成交4比记录,和198号雇员成交3比记录等等。

作者:Tyler Ning
出处:http://www.cnblogs.com/tylerdonet/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,如有问题,可以通过以下邮箱地址williamningdong@gmail.com  联系我,非常感谢。

目录
相关文章
|
10月前
|
SQL 运维 Cloud Native
【SQL Server】数据库开发指南(五)T-SQL 高级查询综合应用与实战
T-SQL 是 SQL Server 的专用版本,提供了一组强大的高级查询功能,包括聚合函数、子查询、连接、视图、窗口函数、共享表达式、递归查询等。这些功能使得 T-SQL 可以轻松处理大量数据,并支持各种复杂的查询和数据操作。本文将介绍 T-SQL 的一些常见高级查询功能和语法,以及如何使用这些功能来优化 SQL Server 数据库的性能和效率。
148 1
【SQL Server】数据库开发指南(五)T-SQL 高级查询综合应用与实战
|
10月前
|
SQL 存储 Oracle
通过sql做数据透视表,数据库表行列转换(pivot和Unpivot用法)(一)
在mssql中大家都知道可以使用pivot来统计数据,实现像excel的透视表功能 一、MSsqlserver中我们通常的用法
305 0
|
SQL 存储 数据挖掘
【SQL Server】数据库开发指南(三)面向数据分析的 T-SQL 编程技巧与实践
T-SQL 指的是 Transact-SQL,是一种针对 Microsoft SQL Server 数据库系统的 SQL 方言。T-SQL 扩展了标准 SQL 语言,提供了更多的功能和特性,包括事务处理、错误处理、游标处理、动态 SQL、存储过程、触发器、用户定义函数等等。
115 0
【SQL Server】数据库开发指南(三)面向数据分析的 T-SQL 编程技巧与实践
|
SQL 数据可视化 数据挖掘
Pandas+ SLS SQL:融合灵活性和高性能的数据透视
Pandas是一个十分强大的python数据分析工具,也是各种数据建模的标准工具。Pandas擅长处理数字型数据和时间序列数据。Pandas的第一大优势在于,封装了一些复杂的代码实现过程,只需要调用接口就行了,避免了编写大量的代码。Pandas的第二大优势在于灵活性,可以实现自动化批量化处理复杂的逻辑,这些工作是Excel等工具是无法完成的。因而Pandas介于Excel和自主编写程序之间,兼具灵活性和简洁性的数据分析工具。
452 0
|
SQL 数据库
SQL Server——T-SQL基础技术
SQL Server——T-SQL基础技术
252 0
SQL Server——T-SQL基础技术
|
SQL 分布式计算 数据挖掘
SQL、Pandas和Spark:如何实现数据透视表?
数据透视表是一个很重要的数据统计操作,最有代表性的当属在Excel中实现(甚至说提及Excel,个人认为其最有用的当属三类:好用的数学函数、便捷的图表制作以及强大的数据透视表功能)。所以,今天本文就围绕数据透视表,介绍一下其在SQL、Pandas和Spark中的基本操作与使用,这也是沿承这一系列的文章之一。
253 0
SQL、Pandas和Spark:如何实现数据透视表?
|
SQL 数据库 索引
【T-SQL基础】01.单表查询-几道sql查询题
【T-SQL基础】01.单表查询-几道sql查询题
125 0
【T-SQL基础】01.单表查询-几道sql查询题
|
存储 SQL .NET
SQL Server 2012 T-SQL 新特性
原文:SQL Server 2012 T-SQL 新特性 序列 Sequence SQL Server 现在将序列当成一个对象来实现,创建一个序列的例子语法如下: CREATE SEQUENCE DemoSequence START WITH 1 INCREMENT BY 1; 使用序列的方法如下所表达的: SELECT VALUE FOR DemoSequence 序列与以前的种子列(identity)的区别很明显,种子列只限于当前列,而序列是一个对象层面的实现,则可以在多个表之间共享。
1092 0
|
SQL XML 数据格式
SQL点滴26—常见T-SQL面试解析
它山之石可以攻玉,这一篇是读别人的博客后写下的,不是原原本本的转载,加入了自己的分析过程和演练。sql语句可以解决很多的复杂业务,避免过多的项目代码,下面几个语句很值得玩味。    1. 已经知道原表year salary2000 10002001 20002002 30002003 4000怎么查询的到下面的结果,就是累积工资year salary2000 10002001 30002002 60002003 10000 思路:这个需要两个表交叉查询得到当前年的所有过往年,然后再对过往年进行聚合。
579 0