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

原文: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,UnitPriceDiscount4 order by ProductID,UnitPriceDiscount

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

图1

  

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

图2

  

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

1 select * from 2 (select sod.ProductPrice,sod.ProductID,sod.UnitPriceDiscount from SalesOrderDetail sod) so3 pivot4 (5 sum(so.ProductPrice) for so.ProductID in([711],[747],[776])6 ) as pt7 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 from2 (select sod.ProductPrice,sod.ProductID,sod.UnitPriceDiscount from SalesOrderDetail sod) so3 pivot4 (5 sum(so.ProductPrice) for so.ProductID in([711],[747],[776])6 ) as pt7 order by UnitPriceDiscount

  

输出的结果如下图3

图3

  

逆透视

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

1 select ProductID,UnitPriceDiscount,ProductPrice2 from3 (select UnitPriceDiscount,Product711,Product747,Product776 from #Temp1) as up14 unpivot(ProductPrice for ProductID in(Product711,Product747,Product776)) as up25 order by ProductID

查询结果如下图4:

?

?图4

?

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

?

???图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表中的制造时间和平均成本,得到如下的结果

图6

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

1 select 2 ‘AverageCost‘ as Cost_Sorted_By_Production_Days,3 [0],[1],[3],[4]4 from5 (select DaysToManufacture,StandardCost from Production.Product) as SourceTable6 pivot7 (avg(StandardCost) for DaysToManufacture in ([0],[1],[3],[4])) as PivotTable

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

图7

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

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

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

图8

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

select distinct(EmployeeID) from Purchasing.PurchaseOrderHeader

查询结果如图9

图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 Emp27415 FROM 16 (SELECT PurchaseOrderID,EmployeeID,VendorID17 FROM Purchasing.PurchaseOrderHeader) p18 PIVOT19 (20 COUNT (PurchaseOrderID)21 FOR EmployeeID IN22 ( [164], [198], [223], [231],[233],[238],[241],[244],[261],[264],[266],[274])23 ) AS pvt24 ORDER BY pvt.VendorID;

查询结果如下图10

图10

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

时间: 2024-10-12 19:36:19

SQL点滴19—T-SQL中的透视和逆透视的相关文章

SQL点滴15—在SQL Server 2008中调用C#程序

原文:SQL点滴15-在SQL Server 2008中调用C#程序 T-SQL的在执行普通的查询的时候是很高效的,但是在执行循环,判断这样的语句的时候效率就不那么的高了.这时可以借助CLR了,我们可以在SQL Server 2008中扩展C#程序来完成循环等过程式的查询,或者其他SQL不便实现的功能.这个随笔中将介绍在SQL Server中扩展C#程序实现正则表达式的替换功能. 新建一个类库程序命名为Regex,打开Visual Studio 2008,点击File,点击New,点击Proje

SQL SERVER技术内幕之7 透视与逆透视

1.透视转换 透视数据(pivoting)是一种把数据从行的状态旋转为列的状态的处理,在这个过程中可能须要对值进行聚合. 每个透视转换将涉及三个逻辑处理阶段,每个阶段都有相关的元素:分组阶段处理相关的分组或行元素,扩展(spreading)阶段处理相关的扩展或列元素,聚合阶段处理相关的聚合元素和聚合函数.例子中的分组元素是empid,扩展元素为custid,聚合函数为SUM(),聚合元素为qty. (1)使用标准SQL进行透视转换 SELECT empid, SUM(CASE WHEN cust

SQL点滴7—使用SQL Server的attach功能出现错误及解决方法

原文:SQL点滴7-使用SQL Server的attach功能出现错误及解决方法 今天用SQL Server 2008的attach功能附加一个数据库,出了点问题,提示的错误是: Unable to open physical file "D:\Documents\Dalt\XXXX.mdf" Operating system error 5: "5(error not found)" (Microsoft SQL Server: Error 5120)"

笔记-Microsoft SQL Server 2008技术内幕:T-SQL语言基础-07 透视、逆透视及分组集

透视转换 透视数据是一种把数据从行的状态旋转为列的状态的处理.每个透视转换将涉及分组.扩展及聚合三个逻辑处理阶段,每个阶段都有相关的元素:分组阶段处理相关的分组或行元素,扩展阶段处理相关的扩展或列元素,聚合阶段处理相关的聚合元素和聚合函数.现在假设有一张表数据如下: 我现在需要查询出下面的结果: 需求分析:需要在结果中为每一个雇员生成一行记录,这就需要对Orders表中的行按照其empid列进行分组:从结果看,还需要为每一个客户生成一个不同的结果列,那么扩展元素就是custid列:最后还需要对数

SQL之透视、逆透视及分组集

透视 假如当前有数据源如下所示: 有一报表需求如下所示: 这一类的需求就称之为数据透视转换.透视转换一般涉及分组.扩展及聚合三个阶段.上面的需求是按照empid进行分组,按照custid对订货量进行扩展,最后进行聚合SUM(qty).数据透视转换其实是存在某种通用查询模板的.下面是上面这个需求的标准SQL解决方案: 1 SELECT empid, 2 SUM(CASE WHEN custid = 'A' THEN qty END) AS A, 3 SUM(CASE WHEN custid = '

SQL点滴17—使用数据库引擎存储过程,系统视图查询,DBA,BI开发人员必备基础知识

原文:SQL点滴17-使用数据库引擎存储过程,系统视图查询,DBA,BI开发人员必备基础知识 在开发过程中会遇到需要弄清楚这个数据库什么时候建的,这个数据库中有多少表,这个存储过程长的什么样子等等信息,今天把自己工作过程中经常用到的一些数据库引擎存储过程,系统视图等等总结一下以备不时之用.下面的知识多是自己总结,有一些参考了MSDN. sp_help 有时候想尽快查出数据库对象的相关信息,这个存储过程就很有用了.使用它可以查询出整个数据库中所有对象的相关信息.直接运行sp_help结果如下图1,

逆透视转换

逆透视转换(unpivoting)是一种把数据从列的状态旋转为行的状态的技术.通常,它涉及查询数据的透视状态,将来自单个记录中多个列的值扩展为单个列中具有相同值的多个记录.换句话说,把透视表中的每个源行潜在地转换成多个行,每行代表源透视表的一个指定的列值. 使用标准SQL 进行逆透视转换 逆透视转换的标准要SQL解决方案非常明确地要实现3个逻辑处理阶段:生成副本.提取元素和删除不相关的交叉. 解决方案的第一步是根据来源表的每一行生成多个副本(为需要逆透视的每个列生成一个副本). SELECT *

《BI那点儿事》数据流转换——逆透视转换

原文:<BI那点儿事>数据流转换--逆透视转换 逆透视转换将来自单个记录中多个列的值扩展为单个列中具有同样值的多个记录,使得非规范的数据集成为较规范的版本.例如,每个客户在列出客户名的数据集中各占一行,在该行的各列中显示购买的产品和数量.逆透视转换将数据集规范之后,客户购买的每种产品在该数据集中各占一行. 我们下一步是进行逆透视.与透视配置不同,逆透视配置相对简单. 你将需要选择透视字段,在这个例子中透视字段是Ham.Soda.Milk.Beer和Chips.透视字段名称将出现在标题为Prod

sql点滴42—mysql中的数据结构

MySQL 的数值数据类型可以大致划分为两个类别,一个是整数,另一个是浮点数或小数.许多不同的子类型对这些类别中的每一个都是可用的,每个子类型支持不同大小的数据,并且 MySQL 允许我们指定数值字段中的值是否有正负之分或者用零填补. 表列出了各种数值类型以及它们的允许范围和占用的内存空间. 类型 大小 范围(有符号) 范围(无符号) 用途 TINYINT 1 字节 (-128,127) (0,255) 小整数值 SMALLINT 2 字节 (-32 768,32 767) (0,65 535)