sqlserver技术内幕<二> 表运算符之pivot
例一: 在Sql Server的帮助文档中,对Pivot函数是这样解释的: 对第一次使用PIVOT函数的朋友来说,这样的解释很难让大家理解,下面编辑用PIVOT函数来实现一个行转列的功能,以便让读者更容易理解该函数. 注意:PIVOT是Sql Server2005的新函数,2005前行转列请参看本站: 先创建一个工资表: Create Table Salary 往表中插入数据: insert into Salary(HrName,Monthly,[Money])? 查看正常的数据: select * from Salary 结果: HrName? Monthly Money select HrName as '姓名',[一月],[二月],[三月] from Salary? 姓名?? 一月???? 二月???? 三月 如果我们将其中的一月改为四月,因为数据源中没有四月的记录,所以四月查询出来应该为Null. 姓名?? 四月??? 二月???? 三月
例二: 在SQLServer 2000环境中,如果要实现交叉表格报表,主要是靠一系列复杂的 SELECT...CASE 语句. 其实现过程请参阅这里T-SQL 交叉报表(行列互换) 交叉查询 旋转查询 在SQLServer 2005中我们可以使用PIVOT关系运算符来实现行列转换. 还是以学生成绩表来举例: id姓名 科目 成绩 1?张三?语文?60 查询后得出: 姓名?语文数学外语 李四?80? 90? 85 --准备数据: ? 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'); '数学','65'); '外语','70'); insert?studentscore?values?('李四','80'); '90'); '85'); insert?studentscore?values?('王五','71'); '75'); insert?studentscore?values?('赵六','64'); '67'); '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关系运算符来实现行列转换 语文]?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运算符内部使用了score和subject这两列,那么肯定是对[name]分组. 所以我们得出,pivot运算符的分组规则是,跟随对象中的那些不在pivot运算符内部的列: 为了好理解我们再写一个例子:
--在ss这个子查询中,多加一列id --那么pivot应该按照name和id进行分组 select?[name],[语文]?as?'语文',[数学]?as?'数学',[外语]?as?'外语' from?(select?score,subject,[name],id?from?studentscore)?as?ss sum(score)?for?subject?in([语文],[数学],[外语]) )?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 ? '60','65','80','90','86'); '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?
)?
?
insert?
into ?
test?
values
(1,
'a'
'b'
id?,??
name ?
'Q1' ?
from ?
test
union?
all
'Q2'?
test
all
'Q3'?
test
all
'Q4'?
test
order?
by ?
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
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |