微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

sqlserver技术内幕<二> 表运算符之pivot

例一:

sql Server的帮助文档中,对Pivot函数是这样解释的:
可以使用 PIVOT 和 UNPIVOT 关系运算符对表值表达式进行操作以获得另一个表。PIVOT 通过将表达式某一列中的唯一值转换为输出中的多个列来转换表值表达式,并在必要时对最终输出中所需的任何其余的列值执行聚合.

对第一次使用PIVOT函数的朋友来说,这样的解释很难让大家理解,下面编辑用PIVOT函数来实现一个行转列的功能,以便让读者更容易理解该函数.

注意:PIVOT是sql Server2005的新函数,2005前行转列请参看本站:
sqlServer中(行列转换)行转列及列转行且加平均值及汇总值

先创建一个工资表:

Create Table Salary
(
HrName varchar(50),
Monthly varchar(50),
Money money
)

往表中插入数据:

insert into Salary(HrName,Monthly,[Money]) 
select '张三','一月','3000' 
union all
select '张三','二月','3200' 
union all
select '张三','三月','3500' 
union all
select '李四','3800' 
union all
select '李四','4200' 
union all
select '李四','3900'
union all
select '张三','2000'

查看正常的数据:

select * from Salary

结果:

HrName  Monthly Money
张三    一月    3000.00
张三    二月    3200.00
张三    三月    3500.00
李四    一月    3800.00
李四    二月    4200.00
李四    三月    3900.00
张三    一月    2000.00


查看行转列后的数据:

select HrName as '姓名',[一月],[二月],[三月] from Salary 
pivot(sum([Money]) for Monthly in ([一月],[三月])) as pvt

姓名   一月     二月     三月
李四  3800.00   4200.00  3900.00
张三  5000.00   3200.00  500.00


注意:
pivot(sum([Money]) for Monthly in ([一月],[三月])) 中的sum([Money]),这里必须是聚合函数,比如是min,max等。
in ([一月],[三月])中的[一月],[三月]即为Monthly的Value,又为新结果集的列名.

如果我们将其中的一月改为四月,因为数据源中没有四月的记录,所以四月查询出来应该为Null.
测试:

姓名   四月    二月     三月
李四   NULL   4200.00   3900.00
张三   NULL   3200.00   3500.00


例二:

sqlServer 2000环境中,如果要实现交叉表格报表,主要是靠一系列复杂的 SELECT...CASE 语句.

其实现过程请参阅这里T-SQL 交叉报表(行列互换) 交叉查询 旋转查询

sqlServer 2005中我们可以使用PIVOT关系运算符来实现行列转换.

还是以学生成绩表来举例:

id姓名 科目 成绩

1 张三 语文 60
2 张三 数学 65
3 张三 外语 70
4 李四 语文 80
5 李四 数学 90
6 李四 外语 85
7 王五 语文 70
8 王五 数学 71
9 王五 外语 75
10 赵六 语文 64
11 赵六 数学 67
12 赵六 外语 76

查询后得出:

姓名 语文数学外语

李四 80  90  85
王五 70  71  75
张三 60  65  70
赵六 64  67  76

--准备数据:

 

select * from sysobjects where [xtype]='u'

go

if exists(select id from sysobjects where name='studentscore')

drop table studentscore--删除与实验冲突的表

create table studentscore--创建实验表

(

[id] int identity(1,1),

[name] nvarchar(20) not null,sans-serif; font-size:14px; line-height:25px"> subject nvarchar(20) not null,sans-serif; font-size:14px; line-height:25px"> score int not null

)

select * from studentscore

--添加实验数据

insert studentscore values ('张三','语文','60');

ottom:0px; color:rgb(51,'数学','65');

ottom:0px; color:rgb(51,'外语','70');

insert studentscore values ('李四','80');

ottom:0px; color:rgb(51,'90');

ottom:0px; color:rgb(51,'85');

insert studentscore values ('王五','71');

ottom:0px; color:rgb(51,'75');

insert studentscore values ('赵六','64');

ottom:0px; color:rgb(51,'67');

ottom:0px; color:rgb(51,'76');

 

使用 SELECT...CASE 语句实现代码如下

select [name],sans-serif; font-size:14px; line-height:25px"> 语文=max(case

when subject='语文' then score else 0

end),

数学=max(case

when subject='数学' then score else 0

外语=max(case

when subject='外语' then score else 0

end)

from studentscore

group by [name]

结果:

 

下面我们使用PIVOT关系运算符来实现行列转换

ottom:0px; color:rgb(51,[语文as '语文',[数学as '数学',[外语as '外语'

from (select score,subject,[name] from studentscore) as ss

pivot

sum(score) for subject in([语文],[数学],[外语])

) as pvt

结果:用较少的代码完成了交叉表格报表

============================

对于这种方法要注意的一点是,我们使用sum()聚合函数,表面上没有指定按什么方式分组,但是自动按照name列分组了.

怎么做到的呢?原来pivot关系运算符会根据前面的对象中的列来自行判断,在这个例子中pivot前面的对象是ss,是个子查询,这个子查询中只有三列,score,subject[name],但是pivot运算符内部使用了scoresubject这两列,那么肯定是对[name]分组.

所以我们得出,pivot运算符的分组规则是,跟随对象中的那些不在pivot运算符内部的列:

为了好理解我们再写一个例子:

--ss这个子查询,多加一列id

--那么pivot应该按照nameid进行分组

select [name],[@H_502_785@语文] as '语文',[@H_502_785@数学] as '数学',[@H_502_785@外语] as '外语'

from (select score,subject,[name],id from studentscore) as ss

sum(score) for subject in([@H_502_785@语文],[@H_502_785@数学],[@H_502_785@外语])

) as pvt

结果:验证了我们的设想

UNPIVOT关系运算符从字面上来看,就知道它的用途正好和PIVOT相反,下面举例说明:

yuwen int not null,sans-serif; font-size:14px; line-height:25px"> shuxue int not null,sans-serif; font-size:14px; line-height:25px"> waiyu int not null

 

ottom:0px; color:rgb(51,'60','65','80','90','86');

ottom:0px; color:rgb(51,'70','71','64','67',sans-serif; font-size:14px; line-height:25px"> 结果: 

 

SELECT id, [name], score

FROM

   (SELECT id,[name], 语文=yuwen, 数学=shuxue, 外语=waiyu

   FROM studentscore) as ss

UNPIVOT

   (score FOR subject IN

      (语文, 数学, 外语)

)AS unpvt

结果:

 

使用union all 代替unpivot功能

create  table  test(id  int , name  varchar (20), Q1  sql keyword" style="white-space:Nowrap; list-style:none; font-family:Consolas, Q2  sql keyword" style="white-space:Nowrap; list-style:none; font-family:Consolas, Q3  sql keyword" style="white-space:Nowrap; list-style:none; font-family:Consolas, Q4 
 
insert  into  test  values (1, 'a' sql plain" style="white-space:Nowrap; list-style:none; font-family:Consolas,1000,2000,4000,5000) 
(2,monospace!important; font-size:1em!important; padding:0px!important; color:blue!important; margin:0px!important; border:0px!important; outline:0px!important; bottom:auto!important; float:none!important; height:auto!important; left:auto!important; line-height:1.1em!important; overflow:visible!important; position:static!important; right:auto!important; top:auto!important; vertical-align:baseline!important; width:auto!important; min-height:inherit!important">'b' sql plain" style="white-space:Nowrap; list-style:none; font-family:Consolas,3000,3500,4200,5500) 
 
select  id ,   name  sql plain" style="white-space:Nowrap; list-style:none; font-family:Consolas,quarter = 'Q1'  sql plain" style="white-space:Nowrap; list-style:none; font-family:Consolas, profile = Q1  from  test
union  all
'Q2'  sql plain" style="white-space:Nowrap; list-style:none; font-family:Consolas, profile = Q2  test
all
'Q3'  sql plain" style="white-space:Nowrap; list-style:none; font-family:Consolas, profile = Q3  test
all
'Q4'  sql plain" style="white-space:Nowrap; list-style:none; font-family:Consolas, profile = Q4  test
order  by  sql plain" style="white-space:Nowrap; list-style:none; font-family:Consolas, quarter
 
drop  test
 
/*
id           name                  quarter profile     
----------- -------------------- ------- ----------- 
1           a                    Q1      1000
1           a                    Q2      2000
1           a                    Q3      4000
1           a                    Q4      5000
2           b                    Q1      3000
2           b                    Q2      3500
2           b                    Q3      4200
2           b                    Q4      5500

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐