MSSQL行列转换

说明:普通行列转换(version  1.0 )仅针对sql server 2000提供静态和动态写法,version  2 .0增加sql server 2005的有关写法。

问题:假设有张学生成绩表(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,指课程不止语文、数学、物理这三门课程。(以下同)
declare   @sql   varchar ( 8000 )
set   @sql   =   ' select 姓名  '
select   @sql   =   @sql   +   '  , max(case 课程 when  '''   +  课程  +   '''  then 分数 else 0 end) [ '   +  课程  +   ' ] '
from  ( select   distinct  课程  from  tb)  as  a
set   @sql   =   @sql   +   '  from tb group by 姓名 '
exec ( @sql

-- SQL SERVER 2005 静态SQL。
select   *   from  ( select   *   from  tb) a pivot ( max (分数)  for  课程  in  (语文,数学,物理)) b

-- SQL SERVER 2005 动态SQL。
declare   @sql   varchar ( 8000 )
select   @sql   =   isnull ( @sql   +   ' ],[ '  ,  '' +  课程  from  tb  group   by  课程
set   @sql   =   ' [ '   +   @sql   +   ' ] '
exec  ( ' select * from (select * from tb) a pivot (max(分数) for 课程 in ( '   +   @sql   +   ' )) b ' )

-- -------------------------------

/*
问题:在上述结果的基础上加平均分,总分,得到如下结果:
姓名 语文 数学 物理 平均分 总分 
---- ---- ---- ---- ------ ----
李四 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   @sql   =   @sql   +   '  , max(case 课程 when  '''   +  课程  +   '''  then 分数 else 0 end) [ '   +  课程  +   ' ] '
from  ( select   distinct  课程  from  tb)  as  a
set   @sql   =   @sql   +   '  , 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。
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 (
'   +   @sql   +   ' )) b) m , 
(select 姓名 , cast(avg(分数*1.0) as decimal(18,2)) 平均分 , sum(分数) 总分 from tb group by 姓名) n
where m.姓名 = n.姓名
' )

drop   table  tb    

-- ----------------
--
----------------

/*
问题:如果上述两表互相换一下:即表结构和数据为:
姓名 语文 数学 物理
张三 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   decimal ( 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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值