数据库行列转换—PIVOT和UNPIVOT运算符的技巧

本文详细介绍了SQL中PIVOT和UNPIVOT操作的原理、使用方法及应用场景,包括具体示例代码和比较分析,旨在帮助读者理解如何在SQL中灵活地进行数据透视与拆分。

原文链接:http://www.cnblogs.com/aierong/archive/2008/09/01/1279463.html

1.简介
PIVOT通过将表达式某一列中的唯一值转换为输出中的多个列来旋转表值表达式,并在必要时对最终输出中所需的任何其余列值执行聚合。
UNPIVOT与PIVOT执行相反的操作,将表值表达式的列转换为列值。
通俗简单的说:PIVOT就是行转列,UNPIVOT就是列传行

2.例题



-- 建立销售表
CREATE TABLE Sell
(
[ Year ] INT ,
[ Quarter ] NVARCHAR ( 10 ),
Quantity
INT
)

-- 插入测试数据
INSERT INTO Sell
VALUES ( 2006 , ' Q1 ' , 20 )
INSERT INTO Sell
VALUES ( 2006 , ' Q2 ' , 15 )
INSERT INTO Sell
VALUES ( 2006 , ' Q2 ' , 4 )
INSERT INTO Sell
VALUES ( 2006 , ' Q3 ' , 12 )
INSERT INTO Sell
VALUES ( 2006 , ' Q4 ' , 18 )

INSERT INTO Sell
VALUES ( 2007 , ' Q1 ' , 10 )
INSERT INTO Sell
VALUES ( 2007 , ' Q2 ' , 10 )

INSERT INTO Sell
VALUES ( 2008 , ' Q1 ' , 8 )
INSERT INTO Sell
VALUES ( 2008 , ' Q2 ' , 7 )
INSERT INTO Sell
VALUES ( 2008 , ' Q3 ' , 5 )
INSERT INTO Sell
VALUES ( 2008 , ' Q3 ' , 10 )
INSERT INTO Sell
VALUES ( 2008 , ' Q4 ' , 9 )
GO



-- 得到每年每季度的销售总数
SELECT *
FROM SellPIVOT( SUM (Quantity) FOR [ Quarter ] IN (Q1,Q2,Q3,Q4)) AS P
GO


--查询得如下结果
--注意:
--如果子组为空,SQL Server生成空值。如果聚合函数是COUNT,且子组为空,则返回零。
Year Q1 Q2 Q3 Q4
2006 20 19 12 18
2007 10 10 NULL NULL
20088 7 15 9

其实PIVOT在sql2000中可以用SELECT...CASE语句来实现,下面是sql2000的代码:

-- sql2000静态版本
SELECT [ year ] ,
SUM ( CASE WHEN [ Quarter ] = ' Q1 ' THEN Quantity
END ) AS Q1,
SUM ( CASE WHEN [ Quarter ] = ' Q2 ' THEN Quantity
END ) AS Q2,
SUM ( CASE WHEN [ Quarter ] = ' Q3 ' THEN Quantity
END ) AS Q3,
SUM ( CASE WHEN [ Quarter ] = ' Q4 ' THEN Quantity
END ) AS Q4
FROM sell
GROUP BY [ year ]

-- sql2000动态版本
DECLARE @sql NVARCHAR ( 2000 )
SELECT @sql = ' select[year] '

SELECT @sql = @sql + ' ,sum(casewhen[Quarter]= ''' + [ Quarter ]
+ ''' thenQuantityend)as ' + [ Quarter ]
FROM sell
GROUP BY [ Quarter ]
ORDER BY [ Quarter ] ASC

select @sql = @sql + ' fromsellgroupby[year] '

execute ( @sql )

UNPIVOT将与PIVOT执行几乎完全相反的操作,将列转换为行。


-- 创建测试表
CREATE TABLE TestUNPIVOT
(
ID
INT ,
A1
NVARCHAR ( 10 ),
A2
NVARCHAR ( 10 ),
A3
NVARCHAR ( 10 )
)

-- 插入测试数据
INSERT INTO TestUNPIVOT
VALUES ( 1 , ' q1 ' , ' q2 ' , ' q3 ' )
INSERT INTO TestUNPIVOT
VALUES ( 2 , ' q1 ' , ' p1 ' , ' m1 ' )
INSERT INTO TestUNPIVOT
VALUES ( 3 , ' t1 ' , ' p1 ' , ' m1 ' )
GO

-- UNPIVOT
SELECT ID,
A,
[ Value ]
FROM ( SELECT ID,
A1,
A2,
A3
FROM TestUNPIVOT
)pUNPIVOT(
[ Value ] FOR A IN (A1,A2,A3)) AS u
ORDER BY id ASC ,
a
ASC
GO

--查询得如下结果
ID A Value
1 A1 q1
1 A2 q2
1 A3 q3
2 A1 q1
2 A2 p1
2 A3 m1
3 A1 t1
3 A2 p1
3 A3 m1



-- UNPIVOT的sql2000实现语句:
SELECT id,
' a1 ' AS [ A ] ,
a1
AS [ Value ]
FROM TestUNPIVOT
UNION ALL
SELECT id,
' a2 ' ,
A2
FROM TestUNPIVOT
UNION ALL
SELECT id,
' a3 ' ,
A3
FROM TestUNPIVOT
ORDER BY id ASC ,a ASC


3.总结
个人感觉PIVOT运算符相比SELECT...CASE语句就是代码精简了一些,似乎PIVOT可读性好像不太好!
至少我看起来PIVOT语法有点怪怪,也许是还习惯吧!我个人还是喜欢用SELECT...CASE语句.
希望微软能提供PIVOT运算符的动态版本,这样动态生成列时,不用那么费事的累加字符串

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值