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

复制代码

透视操作的处理流程是:

  1. 对pivot_column和 aggregated_column的其余column进行分组,即,group by other_columns;
  2. 当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

View Code

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)

View Code

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)

View Code

二,Unpivot用法

unpivot是将列名转换为列值,列名做为列值,因此,会新增两个column:一个column用于存储列名,一个column用于存储列值

复制代码

table_soucr
unpivot
(
newcolumn_store_unpivotcolumn_name for 
newcolumn_store_unpivotcolumn_value in (unpivotcolumn_name_list)  
)

复制代码

逆透视(unpivot)的处理流程是:

  1. unpivotcolumn_name_list是逆透视列的列表,其列值是相兼容的,能够存储在一个column中
  2. 保持其他列(除unpivotcolumn_name_list之外的所有列)的列值不变
  3. 依次将unpivotcolumn的列名存储到newcolumn_store_unpivotcolumn_name字段中,将unpivotcolumn的列值存储到newcolumn_store_unpivotcolumn_value字段中

1,创建示例数据

CREATE TABLE dbo.Venders 
(
    VendorID int, 
    Emp1 int, 
    Emp2 int,  
    Emp3 int, 
    Emp4 int, 
    Emp5 int
);  
GO 
 
INSERT INTO dbo.Venders VALUES (1,4,3,5,4,4);  
INSERT INTO dbo.Venders VALUES (2,4,1,5,5,5);  
INSERT INTO dbo.Venders VALUES (3,4,3,5,4,4);  
INSERT INTO dbo.Venders VALUES (4,4,2,5,5,4);  
INSERT INTO dbo.Venders VALUES (5,5,1,5,5,5);  
GO

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来实现

select VendorID, 'Emp1' as Employee, Emp1 as Orders
from dbo.Venders
union all 
select VendorID, 'Emp2' as Employee, Emp2 as Orders
from dbo.Venders
union all 
select VendorID, 'Emp3' as Employee, Emp3 as Orders
from dbo.Venders
union all
select VendorID, 'Emp4' as Employee, Emp4 as Orders
from dbo.Venders
union all
select VendorID, 'Emp5' as Employee, Emp5 as Orders
from dbo.Venders

View Code

4,动态unpivot的实现,使用动态sql语句

聪明如你,很容易实现,代码就不贴了....

三,性能讨论

pivot和unpivot的性能不是很好,不要用来处理海量的数据

 

参考文档:

Using PIVOT and UNPIVOT

作者悦光阴

出处http://www.cnblogs.com/ljhdo/

 本文版权归作者和博客园所有,欢迎转载,但未经作者同意,必须保留此段声明,且在文章页面醒目位置显示原文连接,否则保留追究法律责任的权利。  








 本文转自悦光阴博客园博客,原文链接:http://www.cnblogs.com/ljhdo/p/4995554.html,如需转载请自行联系原作者

目录
相关文章
|
4月前
|
SQL 数据处理
简单行转列
本文介绍了基于配送订单表的数据处理方法,包括使用 `collect_list`、`collect_set` 和 `sort_array` 函数实现行转列操作。通过 SQL 查询,实现了骑手 ID 和配送品类的统计,并对数据进行了去重和排序处理。此外,还提供了相关函数的详细说明和示例,以及数据准备的 SQL 语句。最后推荐了更多关于行转列和列转行的相关文章。
|
8月前
|
SQL Oracle 关系型数据库
Oracle数据库之PIVOT实现行转列
Oracle数据库之PIVOT实现行转列
226 0
|
SQL 搜索推荐 程序员
explode 列转行的 2 个常用技巧!
explode 列转行的 2 个常用技巧!
explode 列转行的 2 个常用技巧!
|
关系型数据库 Oracle
|
移动开发 关系型数据库 Oracle