行列转换

行列转换,通常有2种方法,一是CASE WHEN/UNION;一是PIVOT/UNPIVOT。对于行值或列数不固定的情况,需要用动态SQL。

一. 行转列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
--drop table RowToCol
create  table  RowToCol
(
ID        int ,
Code      varchar (10),
Value     int
)
Go
insert  RowToCol
select  1, 'Item1' ,1000  union  all
select  1, 'Item2' ,1000  union  all
select  1, 'Item3' ,500   union  all
select  2, 'Item1' ,2000  union  all
select  2, 'Item2' ,0     union  all
select  3, 'Item1' ,1000  union  all
select  3, 'Item3' ,500
GO
select  from  RowToCol

要得到这样的结果:

ID Item1 Item2 Item3
1 1000 1000 500
2 2000 0 0
3 1000 0 500


1. CASE WHEN

在SQL Server 2000时,常用的写法,沿用至今。

(1) 静态

1
2
3
4
5
6
7
8
9
10
11
select  ID,
     sum ( case  Code  when  'Item1'  then  Value  else  end as  Item1,
     sum ( case  Code  when  'Item2'  then  Value  else  end as  Item2,
     sum ( case  Code  when  'Item3'  then  Value  else  end as  Item3
from  RowToCol  group  by  ID
--或者用max也行
select  ID,
     max ( case  Code  when  'Item1'  then  Value  else  end as  Item1,
     max ( case  Code  when  'Item2'  then  Value  else  end as  Item2,
     max ( case  Code  when  'Item3'  then  Value  else  end as  Item3
from  RowToCol  group  by  ID


(2) 动态

在不确定有多少行需要转为列时,先distinct出待转列的值,再拼出包含若干个CASE的SQL语句,然后运行。

1
2
3
4
5
6
7
declare  @sql  varchar (8000)
set  @sql =  'select ID '
select  @sql = @sql +  ' , max(case Code when ' ''  + Code +  '' ' then Value else 0 end) ['  + Code +  ']'
from  ( select  distinct  Code  from  RowToCol)  as  a
set  @sql = @sql +  ' from RowToCol group by ID'
--print @sql
exec (@sql)


2. PIVOT

PIVOT是SQL Server 2005的新语法,Oracle在11g中也推出了这个语法。

(1) 静态

1
2
select  from  ( select  from  RowToCol) a
pivot ( max (value)  for  Code  in  ([Item1],[Item2],[Item3])) b


(2) 动态

用PIVOT拼写动态SQL时就简单了,只要把后面的列清单整理出来就可以了。

1
2
3
4
5
declare  @sql  varchar (8000)
select  @sql =  isnull (@sql +  '],['  '' ) + Code  from  RowToCol  group  by  Code
set  @sql =  '['  + @sql +  ']'
--print @sql
exec  ( 'select * from (select * from RowToCol) a pivot (max(value) for Code in ('  + @sql +  ')) b' )


二. 列转行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
--drop table ColToRow
create  table  ColToRow
(
ID     int ,
Item1  int ,
Item2  int ,
Item3  int
)
GO
insert  into  ColToRow
select  '1' ,1000,1000,500  union  all
select  '2' ,2000,0,0       union  all
select  '3' ,1000,0,500
GO
select  from  ColToRow

要得到这样的结果:

ID Code Value
1 Item1
1000
1 Item2 1000
1 Item3 500
2 Item1 2000
2 Item2 0
2 Item3 0
3 Item1 1000
3 Item2 0
3 Item3 500


1. UNION

在SQL Server 2000时,常用的写法,沿用至今。

(1) 静态

1
2
3
4
5
6
select  ID,Code= 'Item1' ,Value=Item1  from  ColToRow
union  all
select  ID,Code= 'Item2' ,Value=Item2  from  ColToRow
union  all
select  ID,Code= 'Item3' ,Value=Item3  from  ColToRow
order  by  ID

SQL Server对于多个UNION的排序,只要在最后加ORDER BY就可以了。


(2) 动态

在不确定有多少列需要转为行时,先借助系统表syscolumns找出待转行的列,再拼出包含若干个UNION语句,然后运行。

1
2
3
4
5
6
7
declare  @sql  varchar (8000)
select  @sql =  isnull (@sql +  ' union all '  ''  ) +  ' select ID , [Code] = '  + quotename( Name  '' '' ) +  ' , [Value] = '  + quotename( Name ) +  ' from ColToRow'
from  syscolumns
where  name  <> N 'ID'  and  ID = object_id( 'ColToRow' )
order  by  colid  asc
--print @sql
exec (@sql +  ' order by ID ' )


2. UNPIVOT

UNPIVOT是SQL Server 2005的新语法,Oracle在11g中也推出了这个语法。

(1) 静态

1
2
select  ID , Code , Value  from  ColToRow
unpivot (Value  for  Code  in ([Item1] , [Item2] , [Item3])) t


(2) 动态

1
2
3
4
5
6
declare  @sql  varchar (8000)
select  @sql =  isnull (@sql +  '],['  '' ) +  name  from  syscolumns
where  name  <> N 'ID'  and  ID = object_id( 'ColToRow' )
set  @sql =  '['  + @sql +  ']'
--print @sql
exec ( 'select ID , Code , Value from ColToRow unpivot (Value for Code in('  + @sql +  ')) t' )


本文出自 “SQL Server DBA” 博客,请务必保留此出处http://qianzhang.blog.51cto.com/317608/1202793

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值