SQL server 2005 PIVOT运算符的使用

本文涉及的产品
云数据库 RDS SQL Server,独享型 2核4GB
简介: 原文: SQL server 2005 PIVOT运算符的使用         PIVOT,UNPIVOT运算符是SQL server 2005支持的新功能之一,主要用来实现行到列的转换。
原文: SQL server 2005 PIVOT运算符的使用

        PIVOT,UNPIVOT运算符是SQL server 2005支持的新功能之一,主要用来实现行到列的转换。本文主要介绍PIVOT运算符的操作,以及如何实现动态PIVOT的行列转换。

       关于UNPIVOT及SQL server 2000下的行列转换请参照本人的其它文章。

一、PIVOT的语法
SELECT 
  [non-pivoted column], -- optional 
  [additional non-pivoted columns], -- optional 
  [first pivoted column], 
  [additional pivoted columns] 
FROM ( 
  SELECT query producing sql data for pivot 
  -- select pivot columns as dimensions and 
  -- value columns as measures from sql tables 
) AS TableAlias 
PIVOT 
( 

  <aggregation function>(column for aggregation or measure column) -- MIN,MAX,SUM,etc 

  FOR [] 
  IN ( 
    [first pivoted column], ..., [last pivoted column] 
  ) 
) AS PivotTableAlias 
ORDER BY clause – optional

二、PIVOT的使用例子

1. 静态PIVOT的用法
       为演示,从NorthWind数据库中提取一些记录生成新的Orders表,然后使用PIVOT将行转换到列。

USE tempdb
GO
SELECT YEAR(OrderDate) AS [Year]
       ,CustomerID 
       ,od.Quantity
INTO dbo.Orders       
FROM NorthWind..Orders AS o
    JOIN NorthWind..[Order Details] AS od
        ON o.OrderID = od.OrderID
WHERE o.CustomerID IN ('BONAP','BOTTM','ANTON')
SELECT CustomerID
	,[1996],[1997],[1998]
FROM dbo.Orders
PIVOT (
	   SUM(Quantity)
	   FOR [Year] IN ([1996],[1997],[1998])
   )x
/*			   
TSQL中pivot的结构:
    ●  用于生成pivot数据源的源表,作为一个输入表
    ●  pivot表
    ●  聚合列及透视列的选择

TSQL中pivot的实现:
1->上例中Orders表相当于是一个输入表。包含了CustomerID,[Year],Quantity 三个列。
   Year是透视列,用于生成维度。
   pivot首先将聚合列之外的列进行分组,并对其实现聚合。本列中则是对聚合列Quantity之外的列先实现分组,
   即对CustomerID,Year进行分组,并对其Quantity实现聚合,相当于先做如下处理:
*/  			   
SELECT CustomerID
       ,[Year]
       ,SUM(Quantity) AS Total
FROM dbo.Orders
GROUP BY CustomerID
       ,[Year]
ORDER BY CustomerID			   

/*	Result:		   
CustomerID Year        Total
---------- ----------- -----------
ANTON      1996        24
ANTON      1997        295
ANTON      1998        40
BONAP      1996        181
BONAP      1997        486
BONAP      1998        313
BOTTM      1996        81
BOTTM      1997        454
BOTTM      1998        421
*/
/*
2->pivot根据FOR [Year] IN子句中的值,在结果集中来建立对应的新列,本例中即是列,,
   对于新列,,中的取值,取中间结果集中与之相对应的值。
   如对于客户ANTON,1996列中的值就选择中间结果中对应的Total值,同理列中为。
   并将中间结果pivot表命名为x。
   
3->最外层的SELECT语句从pivot表生成最终结果,此处因Orders表仅有列,故直接将结果用一个SELECT返回,有嵌套的SELECT参照下例。
  
--结果:  
CustomerID 1996        1997        1998
---------- ----------- ----------- -----------
ANTON      24          295         40
BONAP      181         486         313
BOTTM      81          454         421
*/         以下是为输入表多于一列的例子,数据来源于SQL server 2005的AdventureWorks,其实现的原理同上。
SELECT *  
FROM(
	SELECT YEAR(DueDate) [Year]
		   ,CASE MONTH(DueDate)
			WHEN 1 THEN 'January' 
			WHEN 2 THEN 'February'
			WHEN 3 THEN 'March'
			WHEN 4 THEN 'April'
			WHEN 5 THEN 'May'
			WHEN 6 THEN 'June'
			WHEN 7 THEN 'July'
			WHEN 8 THEN 'August'
			WHEN 9 THEN 'September'
			WHEN 10 THEN 'October'
			WHEN 11 THEN 'November'
			WHEN 12 THEN 'December'
		   END as [Month]
		   ,ProductID
		   ,OrderQty
	FROM Production.WorkOrder
)WorkOrder
    PIVOT (
           SUM(OrderQty)
           FOR [Month] IN ([January],[February],[March],[April],[May],[June],[July],[August],[September],[October],[November],[December])
          )x
ORDER BY [Year], ProductID  
--Result: 末尾部分省略
/*  
Year        ProductID   January     February    March       April       May         June        July        August      
----------- ----------- ----------- ----------- ----------- ----------- ----------- ----------- ----------- ----------- 
2002        3           8480        16870       12960       9530        19390       14170       26200       35870             
2002        316         1842        3704        2910        2252        4738        3496        7624        10778          
2002        324         1842        3704        2910        2252        4738        3496        7546        10600            
2002        327         921         1852        1455        1126        2369        1748        3773        5300              
2002        328         414         1048        872         458         1272        992         1786        2632         
*/


2. 动态PIVOT的使用

USE AdventureWorks;
GO 

--第一种生成透视列的方法,使用了COALESCE来联接字符串
DECLARE @PivotColHeader VARCHAR(MAX)    
SELECT @PivotColHeader =
    COALESCE(@PivotColHeader + ',[' + cast(Name as varchar) + ']',
    '[' + cast(Name as varchar) + ']')   --示例中Name转换为varchar或char类型,注意:在CAST 和CONVERT 中使用varchar 时,显示n的默认值为30
FROM Sales.SalesTerritory
GROUP BY Name

/*
--第二种生成透视列的方法,使用了FOR XML PATH方法
SELECT @PivotColHeader = 
    STUFF(
    (     
          SELECT DISTINCT ',[' + cast(Name as varchar) + ']'
          FROM Sales.SalesTerritory
          FOR XML PATH('')
    ),
    1,1,'')
*/

DECLARE @PivotTableSQL NVARCHAR(MAX)
SET @PivotTableSQL = N'
    SELECT *
    FROM (
        SELECT YEAR(H.OrderDate) [Year]
			,T.Name
			,H.TotalDue
        FROM Sales.SalesOrderHeader H
			LEFT JOIN Sales.SalesTerritory T
			    ON H.TerritoryID = T.TerritoryID
    )AS PivotData
        PIVOT(
            SUM(TotalDue)
            FOR Name IN (
                         ' + @PivotColHeader + '
                         )
               ) AS x '                            
EXECUTE sp_executesql @PivotTableSQL    

--Result:部分结果省略
/*
Year        Australia             Canada                Central               France                Germany               Northeast             
----------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- 
2001        1446497.1744          2173647.1453          1263884.1024          199531.723            262752.4184           754833.2045           
2002        2380484.8387          7215430.5017          3518185.4756          1717145.7439          575960.0974           3275322.1694          
2003        4547123.2777          8186021.9178          4015356.874           4366078.3475          2714826.4297          3833030.25           
2004        3823410.2386          3926712.8926          1771532.7396          2853948.6596          2386224.5508          1406555.6861         

*/   

   对该动态pivot增加汇总列

DECLARE @PivotColHeader VARCHAR(MAX)
DECLARE @TotalCol VARCHAR(MAX)

SELECT @PivotColHeader =                              --使用COALESCE函数生成列标题
    COALESCE(@PivotColHeader + ',[' + cast(Name as varchar) + ']',
    '[' + cast(Name as varchar) + ']')
    ,
    @TotalCol = COALESCE(@TotalCol + ', SUM([' + cast(Name as varchar) + ']) AS [' + cast(Name as varchar) + ']'
     ,'SUM([' + cast(Name as varchar) + ']) AS [' + cast(Name as varchar) + ']')     --使用COALESCE函数生成汇总字符串
FROM Sales.SalesTerritory

DECLARE @PivotTableSQL NVARCHAR(MAX)
SET @PivotTableSQL = N'
    SELECT *
    FROM (
        SELECT CAST(YEAR(H.OrderDate) AS CHAR(4)) [Year]
		,T.Name
		,H.TotalDue
        FROM Sales.SalesOrderHeader H
		LEFT JOIN Sales.SalesTerritory T
		   ON H.TerritoryID = T.TerritoryID
    )AS PivotData
		PIVOT(
			SUM(TotalDue)
			FOR Name IN (
			 ' + @PivotColHeader + '
				   )
		    ) AS x   
    UNION 
    SELECT ''GrandTotal'', ' + @TotalCol + '
    FROM (
	SELECT CAST(YEAR(H.OrderDate) AS CHAR(4)) [Year]
		,T.Name
		,H.TotalDue
	FROM Sales.SalesOrderHeader H
	    LEFT JOIN Sales.SalesTerritory T
		ON H.TerritoryID = T.TerritoryID
	) AS PivotData													
		PIVOT(
			SUM(TotalDue)
			FOR Name IN (
				' + @PivotColHeader + '
				   )
		     ) AS y '   
--PRINT  @PivotTableSQL                                        
EXECUTE sp_executesql @PivotTableSQL 

--Result:部分结果省略
/*
Year       Australia             Canada                Central               France                Germany               Northeast             Northwest             
---------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- --------------------- 
2001       1446497.1744          2173647.1453          1263884.1024          199531.723            262752.4184           754833.2045           2703481.7947          
2002       2380484.8387          7215430.5017          3518185.4756          1717145.7439          575960.0974           3275322.1694          5651688.6685          
2003       4547123.2777          8186021.9178          4015356.874           4366078.3475          2714826.4297          3833030.25            7494658.0357          
2004       3823410.2386          3926712.8926          1771532.7396          2853948.6596          2386224.5508          1406555.6861          4952772.2793          
GrandTotal 12197515.5294         21501812.4574         10568959.1916         9136704.474           5939763.4963          9269741.31            20802600.7782         
*/    

生成汇总列的注意事项;
    1->使用COALESCE函数生成列标题 。
    2->使用COALESCE函数生成带有SUM求和函数并且指定了别名的字符串。
    3->使用UNION对两个SELECT来实现联接。且将[Year]转换为字符串,因为YEAR(H.OrderDate)得值为 INT ,而''GrandTotal''为字符串,UNION 或UNION ALL使用时必须列的数量和类型相对应。

 

 

相关实践学习
使用SQL语句管理索引
本次实验主要介绍如何在RDS-SQLServer数据库中,使用SQL语句管理索引。
SQL Server on Linux入门教程
SQL Server数据库一直只提供Windows下的版本。2016年微软宣布推出可运行在Linux系统下的SQL Server数据库,该版本目前还是早期预览版本。本课程主要介绍SQLServer On Linux的基本知识。 相关的阿里云产品:云数据库RDS&nbsp;SQL Server版 RDS SQL Server不仅拥有高可用架构和任意时间点的数据恢复功能,强力支撑各种企业应用,同时也包含了微软的License费用,减少额外支出。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/sqlserver
目录
相关文章
|
12天前
|
SQL 人工智能 算法
【SQL server】玩转SQL server数据库:第二章 关系数据库
【SQL server】玩转SQL server数据库:第二章 关系数据库
51 10
|
22天前
|
SQL
启动mysq异常The server quit without updating PID file [FAILED]sql/data/***.pi根本解决方案
启动mysq异常The server quit without updating PID file [FAILED]sql/data/***.pi根本解决方案
17 0
|
12天前
|
SQL 算法 数据库
【SQL server】玩转SQL server数据库:第三章 关系数据库标准语言SQL(二)数据查询
【SQL server】玩转SQL server数据库:第三章 关系数据库标准语言SQL(二)数据查询
75 6
|
7天前
|
SQL 安全 网络安全
IDEA DataGrip连接sqlserver 提示驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接的解决方法
IDEA DataGrip连接sqlserver 提示驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接的解决方法
17 0
|
12天前
|
SQL 存储 数据挖掘
数据库数据恢复—RAID5上层Sql Server数据库数据恢复案例
服务器数据恢复环境: 一台安装windows server操作系统的服务器。一组由8块硬盘组建的RAID5,划分LUN供这台服务器使用。 在windows服务器内装有SqlServer数据库。存储空间LUN划分了两个逻辑分区。 服务器故障&初检: 由于未知原因,Sql Server数据库文件丢失,丢失数据涉及到3个库,表的数量有3000左右。数据库文件丢失原因还没有查清楚,也不能确定数据存储位置。 数据库文件丢失后服务器仍处于开机状态,所幸没有大量数据写入。 将raid5中所有磁盘编号后取出,经过硬件工程师检测,没有发现明显的硬件故障。以只读方式将所有磁盘进行扇区级的全盘镜像,镜像完成后将所
数据库数据恢复—RAID5上层Sql Server数据库数据恢复案例
|
16天前
|
SQL 数据安全/隐私保护
SQL Server 2016安装教程
SQL Server 2016安装教程
17 1
|
16天前
|
SQL 安全 Java
SQL server 2017安装教程
SQL server 2017安装教程
15 1
|
存储 SQL 程序员
【Sql Server】存储过程通过作业定时执行按天统计记录
通过前两篇文章的学习,我们已经对创建表、存储过程、作业等功能点有所了解 本次将结合前面所学习的知识点,创建统计表以及结合作业定时按天以及实时统计域名各个长度的记录值
304 0
【Sql Server】存储过程通过作业定时执行按天统计记录
|
9月前
|
存储 SQL 数据库
SQL Server——为什么要使用存储过程?不使用是什么样的?
提高数据库执行速度,可能第一次见到这句话的小伙伴们感觉到非常的匪夷所思叭!怎么就提高了它的执行速度捏,从哪方面可以表现出来呢?既然这里要说到的是为什么要使用存储过程,也就是说它的优点是什么。那我们肯定就要对使用和不使用存储过程两方面来进行对比才能看出它的优点对吧。
|
存储 SQL Go
SQL Server 存储过程
SQL Server 存储过程
118 0