当前位置: 代码迷 >> SQL >> SQL Server中的行列转换有关问题
  详细解决方案

SQL Server中的行列转换有关问题

热度:107   发布时间:2016-05-05 12:23:44.0
SQL Server中的行列转换问题

?

SQL Server中的行列转换问题
?
普通行列转换仅针对sql?server?2000提供静态和动态写法。
?
增加sql?server?2005的有关写法。
?

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

?
?
?
经典案例:
?
问题:假设有张学生成绩表(tb)如下:
姓名?课程?分数
张三?语文?74
张三?数学?83
张三?物理?93
李四?语文?74
李四?数学?84
李四?物理?94
想变成(得到如下结果):?
姓名?语文?数学?物理?
----?----?----?----
李四?74???84???94
张三?74???83???93
-------------------
*/
?
create?table?tb(姓名?varchar(10)?,?课程?varchar(10)?,?分数?int)
insert?into?tb?values('张三'?,?'语文'?,?74)
insert?into?tb?values('张三'?,?'数学'?,?83)
insert?into?tb?values('张三'?,?'物理'?,?93)
insert?into?tb?values('李四'?,?'语文'?,?74)
insert?into?tb?values('李四'?,?'数学'?,?84)
insert?into?tb?values('李四'?,?'物理'?,?94)
go
?
--SQL?SERVER?2000?静态SQL,指课程只有语文、数学、物理这三门课程。(以下同)
select?姓名?as?姓名?,
??max(case?课程?when?'语文'?then?分数?else?0?end)?语文,
??max(case?课程?when?'数学'?then?分数?else?0?end)?数学,
??max(case?课程?when?'物理'?then?分数?else?0?end)?物理
from?tb
group?by?姓名
?
--SQL?SERVER?2000?动态SQL,指课程不止语文、数学、物理这三门课程。(以下同)
--变量按sql语言顺序赋值
declare?@sql?varchar(8000)
set?@sql?=?'select?姓名?'
select?@[email protected]+?'?,?max(case?课程?when?'''?+?课程?+?'''?then?分数?else?0?end
)?['?+?课程?+?']'
from?(select?distinct?课程?from?tb)?as?a --同from tb group by课程,默认按课程名排序
set?@[email protected]+?'?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)

?
?
--SQL?SERVER?2005?静态SQL。
select?*?from?tb?pivot?(max(分数)?for?课程?in?(语文,数学,物理))?a
?
--SQL?SERVER?2005?动态SQL。
--使用isnull()
declare?@sql?varchar(8000)
select?@sql?=?isnull(@sql?+?','?,?'')?+?课程?from?tb?group?by?课程
exec?('select?*?from?tb?pivot?(max(分数)?for?课程?in?('?[email protected]+?'))?a')
?
?

--使用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)

?
-----------------------------------
?
/*
问题:在上述结果的基础上加平均分,总分,得到如下结果:
姓名?语文?数学?物理?平均分?总分?
----?----?----?----?------?----
李四?74???84???94???84.00??252
张三?74???83???93???83.33??250
*/
?
--SQL?SERVER?2000?静态SQL。
select?姓名?姓名,
??max(case?课程?when?'语文'?then?分数?else?0?end)?语文,
??max(case?课程?when?'数学'?then?分数?else?0?end)?数学,
??max(case?课程?when?'物理'?then?分数?else?0?end)?物理,
??cast(avg(分数*1.0)?as?decimal(18,2))?平均分,
??sum(分数)?总分
from?tb
group?by?姓名
?
--SQL?SERVER?2000?动态SQL。
declare?@sql?varchar(8000)
set?@sql?=?'select?姓名?'
select?@[email protected]+?',?max(case?课程?when?'''?+?课程?+?'''?then?分数?else?0?end)
?['?+?课程?+?']'
from?(select?distinct?课程?from?tb)?as?a
set?@[email protected]+?'?,?cast(avg(分数*1.0)?as?decimal(18,2))?平均分?,?sum(分数)?总分
?from?tb?group?by?姓名'
exec(@sql)?
?
--SQL?SERVER?2005?静态SQL。
select?m.*?,?n.平均分?,?n.总分?from
(select?*?from?(select?*?from?tb)?a?pivot?(max(分数)?for?课程?in?(语文,数学,物理))
?b)?m,
(select?姓名?,?cast(avg(分数*1.0)?as?decimal(18,2))?平均分,?sum(分数)?总分?from?tb
?group?by?姓名)?n
where?m.姓名?=?n.姓名
?
--SQL?SERVER?2005?动态SQL。
--使用isnull()
declare?@sql?varchar(8000)
select?@sql?=?isnull(@sql?+?','?,?'')?+?课程?from?tb?group?by?课程
exec?('select?m.*?,?n.平均分?,?n.总分?from
(select?*?from?(select?*?from?tb)?a?pivot?(max(分数)?for?课程?in?('?[email protected]+?'))
?b)?m?,?
(select?姓名?,?cast(avg(分数*1.0)?as?decimal(18,2))?平均分,?sum(分数)?总分?from?tb
?group?by?姓名)?n
where?m.姓名?=?n.姓名')
?
drop?table?tb????
?
?

?

--使用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)

?
------------------------------
------------------------------
?
/*
问题:如果上述两表互相换一下:即表结构和数据为:
姓名?语文?数学?物理
张三?74  83  93
李四?74  84  94
想变成(得到如下结果):?
姓名?课程?分数?
----?----?----
李四?语文?74
李四?数学?84
李四?物理?94
张三?语文?74
张三?数学?83
张三?物理?93
--------------
*/
?
create?table?tb(姓名?varchar(10)?,?语文?int?,?数学?int?,?物理?int)
insert?into?tb?values('张三',74,83,93)
insert?into?tb?values('李四',74,84,94)
go
?
--SQL?SERVER?2000?静态SQL。
select?*?from
(
?select?姓名?,?课程?=?'语文'?,?分数?=?语文?from?tb?
?union?all
?select?姓名?,?课程?=?'数学'?,?分数?=?数学?from?tb
?union?all
?select?姓名?,?课程?=?'物理'?,?分数?=?物理?from?tb
)?t
order?by?姓名?,?case?课程?when?'语文'?then?1?when?'数学'?then?2?when?'物理'?then?3
?end
?
--SQL?SERVER?2000?动态SQL。
--调用系统表动态生态。
declare?@sql?varchar(8000)
select?@sql?=?isnull(@sql?+?'?union?all?'?,?''?)?+?'?select?姓名?,?[课程]?=?'?+?
quotename(Name?,?'''')?+?'?,?[分数]?=?'?+?quotename(Name)?+?'?from?tb'
from?syscolumns?
where?name!?=?N'姓名'?and?ID?=?object_id('tb')?--表名tb,不包含列名为姓名的其它列
order?by?colid?asc
exec(@sql?+?'?order?by?姓名?')
?
--SQL?SERVER?2005?动态SQL。
select?姓名,?课程,?分数?from?tb?unpivot?(分数?for?课程?in([语文],?[数学],?[物理]))?
t
?
--SQL?SERVER?2005?动态SQL,同SQL?SERVER?2000?动态SQL。
?
--------------------
/*
问题:在上述的结果上加个平均分,总分,得到如下结果:
姓名?课程???分数
----?------?------
李四?语文???74.00
李四?数学???84.00
李四?物理???94.00
李四?平均分?84.00
李四?总分???252.00
张三?语文???74.00
张三?数学???83.00
张三?物理???93.00
张三?平均分?83.33
张三?总分???250.00
------------------
*/
?
select?*?from
(
?select?姓名?as?姓名?,?课程?=?'语文'?,?分数?=?语文?from?tb?
?union?all
?select?姓名?as?姓名?,?课程?=?'数学'?,?分数?=?数学?from?tb
?union?all
?select?姓名?as?姓名?,?课程?=?'物理'?,?分数?=?物理?from?tb
?union?all
?select?姓名?as?姓名?,?课程?=?'平均分'?,?分数?=?cast((语文?+?数学?+?物理)*1.0/3?as?d
ecimal(18,2))?from?tb
?union?all
?select?姓名?as?姓名?,?课程?=?'总分'?,?分数?=?语文?+?数学?+?物理?from?tb)?t
order?by?姓名?,?case?课程?when?'语文'?then?1?when?'数学'?then?2?when?'物理'?then?3
?when?'平均分'?then?4?when?'总分'?then?5?end
?
drop?table?tb
?
?
?
?

?

  相关解决方案