Pivot 和 Unpivot
Pivot 和 Unpivot
在TSQL中,使用Pivot和Unpivot运算符将一个关系表转换成另外一个关系表,两个命令实现的操作是“相反”的,但是,pivot之后,不能通过unpivot将数据还原。这两个运算符的操作数比较复杂,记录一下自己的总结,以后用到时,作为参考。
一,Pivot用法
Pivot旋转的作用,是将关系表(table_source)中的列(pivot_column)的值,转换成另一个关系表(pivot_table)的列名:
table_source
pivot
(
aggregation_function(aggregated_column)
for pivot_column in ([pivot_column_value_list])
) as pivot_table_alias
透视操作的处理流程是:
- 对pivot_column和 aggregated_column的其余column进行分组,即,group by other_columns;
- 当pivot_column值等于某一个指定值,计算aggregated_column的聚合值;
在使用透视命令时,需要注意:
- pivot将table_source旋转成透视表(pivot_table)之后,不能再被引用
- pivot_column的列值,必须使用中括号([])界定符
- 必须显式命名pivot_table的别名
1,创建示例数据
use tempdb
go
drop table if exists dbo.usr
go
create table dbo.usr
(
name varchar(10),
score int,
class varchar(8)
)
go
insert into dbo.usr
values('a',20,'math'),('b',21,'math'),('c',22,'phy'),('d',23,'phy')
,('a',22,'phy'),('b',23,'phy'),('c',24,'math'),('d',25,'math')
go

2,对name进行分组,对score进行聚合,将class列的值转换为列名
select p.name,p.math,p.phy
from dbo.usr u
pivot
(
sum(score)
for class in([math],[phy])
) as p

3,pivot的等价写法:使用case when语句实现
pivot命令的执行流程很简单,使用caseh when子句实现pivot的功能
select u.name,
sum(case when u.class='math' then u.score else null end) as math,
sum(case when u.class='phy' then u.score else null end) as phy
from dbo.usr u
group by u.name
使用group by子句对name列分组,使用 case when 语句将pivot_column的列值作为列名返回,并对aggregated_column计算聚合值。
4,动态Pivot写法
静态pivot写法的弊端是:如果pivot_column的列值发生变化,静态pivot不能对新增的列值进行透视,变通方法是使用动态sql,拼接列值
Script1,使用case-when子句实现
declare @sql nvarchar(max)
declare @columnlist nvarchar(max)
set @columnlist=N''
;with cte as
(
select distinct class
from dbo.usr
)
select @columnlist+='sum(case when u.class='''+cast(class as varchar(10))+N''' then u.score else null end) as ['+cast(class as varchar(10))+N'],'
from cte
select @columnlist=SUBSTRING(@columnlist,1,len(@columnlist)-1)
select @sql=
N'select u.name,'
+@columnlist
+N'from dbo.usr u
group by u.name'
exec(@sql)
Script2,使用pivot子句实现
declare @sql nvarchar(max)
declare @classlist nvarchar(max)
set @classlist=N''
;with cte as
(
select distinct class
from dbo.usr
)
select @classlist+=N'['+cast(class as varchar(11))+N'],'
from cte
select @classlist=SUBSTRING(@classlist,1,len(@classlist)-1)
select @sql=N'select p.name,'+@classlist+
N' from dbo.usr u
PIVOT
(
sum(score)
for class in('+@classlist+N')
) as p'
exec (@sql)
二,Unpivot用法
unpivot是将列名转换为列值,列名做为列值,因此,会新增两个column:一个column用于存储列名,一个column用于存储列值
table_soucr
unpivot
(
newcolumn_store_unpivotcolumn_name for
newcolumn_store_unpivotcolumn_value in (unpivotcolumn_name_list)
)
逆透视(unpivot)的处理流程是:
- unpivotcolumn_name_list是逆透视列的列表,其列值是相兼容的,能够存储在一个column中
- 保持其他列(除unpivotcolumn_name_list之外的所有列)的列值不变
- 依次将unpivotcolumn的列名存储到newcolumn_store_unpivotcolumn_name字段中,将unpivotcolumn的列值存储到newcolumn_store_unpivotcolumn_value字段中
1,创建示例数据
View Code
2,unpivot用法示例
将Emp1, Emp2, Emp3, Emp4, Emp5的列名和列值存储到字段:Employee和Orders中
SELECT VendorID, Employee, Orders
FROM dbo.Venders as p
UNPIVOT
(Orders FOR Employee IN
(Emp1, Emp2, Emp3, Emp4, Emp5)
)AS unpvt;
GO

3,unpivot可以使用union all来实现
View Code4,动态unpivot的实现,使用动态sql语句
聪明如你,很容易实现,代码就不贴了....
三,性能讨论
pivot和unpivot的性能不是很好,不要用来处理海量的数据
参考文档:

浙公网安备 33010602011771号