SQL Server中行列转换 Pivot UnPivot
PIVOT用于将列值旋转为列名(即行转列),在SQL Server 2000可以用聚合函数配合
CASE
语句实现
PIVOT的一般语法是:PIVOT(聚合函数(列)
FOR
列
in
(…) )
AS
P
完整语法:
table_source
PIVOT(
聚合函数(value_column)
FOR
pivot_column
IN
(<column_list>)
)
UNPIVOT用于将列明转为列值(即列转行),在SQL Server 2000可以用
UNION
来实现
完整语法:
table_source
UNPIVOT(
value_column
FOR
pivot_column
IN
(<column_list>)
)
注意:PIVOT、UNPIVOT是SQL Server 2005 的语法,使用需修改数据库兼容级别
在数据库属性->选项->兼容级别改为 90
典型实例
一、行转列
1、建立表格
ifobject_id(
'tb'
)isnotnulldroptabletb
go
createtabletb(姓名
varchar
(10),课程
varchar
(10),分数
int
)
insertintotbvalues(
'张三'
,
'语文'
,74)
insertintotbvalues(
'张三'
,
'数学'
,83)
insertintotbvalues(
'张三'
,
'物理'
,93)
insertintotbvalues(
'李四'
,
'语文'
,74)
insertintotbvalues(
'李四'
,
'数学'
,84)
insertintotbvalues(
'李四'
,
'物理'
,94)
go
select
*fromtb
go
姓名 课程 分数
---------- ---------- -----------
张三 语文 74
张三 数学 83
张三 物理 93
李四 语文 74
李四 数学 84
李四 物理 94
2、使用SQL Server 2000静态SQL
--c
select
姓名,
max
(
case
课程
when
'语文'
then
分数else0end)语文,
max
(
case
课程
when
'数学'
then
分数else0end)数学,
max
(
case
课程
when
'物理'
then
分数else0end)物理
fromtb
groupby姓名
姓名 语文 数学 物理
---------- ----------- ----------- -----------
李四 74 84 94
张三 74 83 93
3、使用SQL Server 2000动态SQL
--SQL SERVER 2000动态SQL,指课程不止语文、数学、物理这三门课程。(以下同)
--变量按sql语言顺序赋值
declare
@sqlvarchar(500)
set
@sql=
'select姓名'
select
@sql=@sql+
',max(case课程when '
''
+课程+
''
' then分数else 0 end)['
+课程+
']'
from
(selectdistinct课程fromtb)a
--同from tb group by课程,默认按课程名排序
set
@sql=@sql+
' from tb group by姓名'
exec
(@sql)
--使用isnull(),变量先确定动态部分
declare
@sqlvarchar(8000)
select
@sql=
isnull
(@sql+
','
,
''
)+
' max(case课程when '
''
+课程+
''
' then分数else 0 end) ['
+课程+
']'
from
(selectdistinct课程fromtb)asa
set
@sql=
'select姓名,'
+@sql+
' from tb group by姓名'
exec
(@sql)
姓名 数学 物理 语文
---------- ----------- ----------- -----------
李四 84 94 74
张三 83 93 74
4、使用SQL Server 2005静态SQL
select
*fromtb pivot(
max
(分数)
for
课程
in
(语文,数学,物理))a
5、使用SQL Server 2005动态SQL
--使用stuff()
declare
@sqlvarchar(8000)
set
@sql=
''
--初始化变量@sql
select
@sql=@sql+
','
+课程fromtbgroupby课程
--变量多值赋值
set
@sql=stuff(@sql,1,1,
''
)
--去掉首个','
set
@sql=
'select * from tb pivot (max(分数) for课程in ('
+@sql+
'))a'
exec
(@sql)
--或使用isnull()
declare
@sqlvarchar(8000)
–-获得课程集合
select
@sql=
isnull
(@sql+
','
,
''
)+课程fromtbgroupby课程
set
@sql=
'select * from tb pivot (max(分数) for课程in ('
+@sql+
'))a'
exec
(@sql)
二、行转列结果加上总分、平均分
1、使用SQL Server 2000静态SQL
--SQL SERVER 2000静态SQL
select
姓名,
max
(
case
课程
when
'语文'
then
分数else0end)语文,
max
(
case
课程
when
'数学'
then
分数else0end)数学,
max
(
case
课程
when
'物理'
then
分数else0end)物理,
sum
(分数)总分,
cast
(
avg
(分数*1.0)asdecimal(18,2))平均分
fromtb
groupby姓名
姓名 语文 数学 物理 总分 平均分
---------- ----------- ----------- ----------- -----------
李四 74 84 94 252 84.00
张三 74 83 93 250 83.33
2、使用SQL Server 2000动态SQL
--SQL SERVER 2000动态SQL
declare
@sqlvarchar(500)
set
@sql=
'select姓名'
select
@sql=@sql+
',max(case课程when '
''
+课程+
''
' then分数else 0 end)['
+课程+
']'
from
(selectdistinct课程fromtb)a
set
@sql=@sql+
',sum(分数)总分,cast(avg(分数*1.0) as decimal(18,2)) 平均分from tb group by姓名'
exec
(@sql)
3、使用SQL Server 2005静态SQL
selectm.*,n.总分,n.平均分
from
(
select
*fromtb pivot(
max
(分数)
for
课程
in
(语文,数学,物理))a)m,
(
select
姓名,
sum
(分数)总分,
cast
(
avg
(分数*1.0)asdecimal(18,2))平均分
fromtb
groupby姓名)n
wherem.姓名=n.姓名
4、使用SQL Server 2005动态SQL
--使用stuff()
--
declare
@sqlvarchar(8000)
set
@sql=
''
--初始化变量@sql
select
@sql=@sql+
','
+课程fromtbgroupby课程
--变量多值赋值
--同select @sql = @sql + ','+课程from (select distinct课程from tb)a
set
@sql=stuff(@sql,1,1,
''
)
--去掉首个','
set
@sql=
'select m.* , n.总分,n.平均分from
(select * from (select * from tb) a pivot (max(分数) for课程in ('
+@sql+
')) b) m ,
(select姓名,sum(分数)总分, cast(avg(分数*1.0) as decimal(18,2))平均分from tb group by姓名) n
where m.姓名= n.姓名'
exec
(@sql)
--或使用isnull()
declare
@sqlvarchar(8000)
select
@sql=
isnull
(@sql+
','
,
''
)+课程fromtbgroupby课程
set
@sql=
'select m.* , n.总分,n.平均分from
(select * from (select * from tb) a pivot (max(分数) for课程in ('
+
@sql+
')) b) m ,
(select姓名,sum(分数)总分, cast(avg(分数*1.0) as decimal(18,2))平均分from tb group by姓名) n
where m.姓名= n.姓名'
exec
(@sql)
二、列转行
1、建立表格
ifobject_id(
'tb'
)isnotnulldroptabletb
go
createtabletb(姓名
varchar
(10),语文
int
,数学
int
,物理
int
)
insertintotbvalues(
'张三'
,74,83,93)
insertintotbvalues(
'李四'
,74,84,94)
go
select
*fromtb
go
姓名 语文 数学 物理
---------- ----------- ----------- -----------
张三 74 83 93
李四 74 84 94
2、使用SQL Server 2000静态SQL
--SQL SERVER 2000静态SQL。
select
*
from
(
select
姓名,课程=
'语文'
,分数=语文fromtb
unionall
select
姓名,课程=
'数学'
,分数=数学fromtb
unionall
select
姓名,课程=
'物理'
,分数=物理fromtb
) t
orderby姓名,
case
课程
when
'语文'
then1when
'数学'
then2when
'物理'
then3end
姓名 课程 分数
---------- ---- -----------
李四 语文 74
李四 数学 84
李四 物理 94
张三 语文 74
张三 数学 83
张三 物理 93
2、使用SQL Server 2000动态SQL
--SQL SERVER 2000动态SQL。
--调用系统表动态生态。
declare
@sqlvarchar(8000)
select
@sql=
isnull
(@sql+
' union all '
,
''
)+
' select姓名, [课程]='
+quotename(
Name
,
''
''
)+
' , [分数] = '
+quotename(
Name
)+
' from tb'
fromsyscolumns
whereName!=
'姓名'
andID=object_id(
'tb'
)
--表名tb,不包含列名为姓名的其他列
orderbycolid
exec
(@sql+
' order by姓名'
)
go
3、使用SQL Server 2005静态SQL
--SQL SERVER 2005动态SQL
select
姓名,课程,分数fromtb unpivot (分数
for
课程
in
([语文],[数学],[物理])) t
4、使用SQL Server 2005动态SQL
--SQL SERVER 2005动态SQL
declare
@sqlnvarchar(4000)
select
@sql=
isnull
(@sql+
','
,
''
)+quotename(
Name
)
fromsyscolumns
whereID=object_id(
'tb'
)andNamenotin(
'姓名'
)
orderbyColid
set
@sql=
'select姓名,[课程],[分数] from tb unpivot ([分数] for [课程] in('
+@sql+
'))b'
exec
(@sql)