行转列的动态方法

原来的静态方法:

比如有表 t1

Id subj mark

1 Chinese 89

1 Maths 98

2 Chinese 100

2 Maths 78

2 English 100

3 Chinese 99

转换为

id,Chinese,Maths,English 的格式

可以是

(sql#1)

Select id,max(Chinese) as Chinese,max(Maths) as Maths,max(English) as English

From

(

Select id

,case  when(subj =’Chinese’) then mark  else 0  end as [Chinese]

,case  when(subj =’Maths’) then mark  else 0 end as [Maths]’

,case  when(subj =’English’) then mark  else 0 end as [English]

 

From t1) as t2

 

倘若里面有一百个科目呢?你也要写100case?

这里有个动态的方法,在介绍之前,

先把上面的写法换一个形式

 

(sql#2)

Select id

,Chinese = max(case when subj =’Chinese’ then mark else 0 end)

,Maths = max(case when subj =’Maths’ then mark else 0 end)

,English = max( case when subj =’English’ then mark else 0 end)

From t1

Group by id

与前面的区别在于,前面是先构造了下面的表

Id Chinese Maths English

1 89       0     0

1 0       98     0

2 100      0     0

2 0        78    0

2 0         0    100

3 99

然后再按id进行group by,取得各列的最大值.

 

这里呢,其实还是这样的,只是这个过程被迷惑了(根本没有取消这个过程)

由于maxgroup 是最后进行的,所以

上面的sql其实就是先统计了如上的一个表

之后再group by ,max

 

下面进入正题,动态的生成上面的语句

declare @sql varchar(8000)
set @sql='select [id], '

--语句的构造由一个select 语句完成,即按照
select @sql=@sql+quotename(subj)+'=max(case when style='+quotename(subj, '''')+' then rtrim(amount) else ''-'' end),' from t1group by subj
--除去末尾的那个逗号.

select @sql=left(@sqllen(@sql)-1), @sql=@sql+' from t1group by [id]'
exec(@sql)

 

说明:quotename(字符串)把一个unicode字符变为sql server的标识符,这里是列名.

       quotename(字符串,’’’’)是把列名显示为varchar的形式以便于比较.

 

同时也看到select set在赋值方面是差别很大的.以前只是认为set只能一次赋值一个,select可以给多个

现在呢,应该是  set只能赋值一次,select可以多次.

 

从数学上看,

Sql#1 sql#2的差别在于

前者相当于

F(g(x1),g(x2),g(x3))

后者相当于

F(g(x1,x2,x3))

其中g(x)相当于case操作,即列转换操作

F(x) 相当于求最值操作.

 

那么下面的题目就容易理解了

create table T(名字 varchar(10), 科目 varchar(10), 分数 int)
insert T select '1''语文'90
union all select '1''数学'80
union all select '2''语文'90
union all select '2''数学'85
union all select '2''外语'70

declare @sql varchar(8000)
declare @sql2 varchar(1000)
set @sql=''
set @sql2='總分='
select @sql=@sql+quotename(科目)+'=isnull( max(case when 科目='+quotename(科目'''')+' then 分数 end), 100),',
@sql2=@sql2+'tmp.'+科目+'+'
from T
group by 科目
select
@sql2=left(@sql2len(@sql2)-1),
@sql=left(@sqllen(@sql)-1),
@sql='select tmp.*,'+@sql2+' from (select 名字,'+@sql,
@sql=@sql+' from T group by 名字) tmp'
exec(@sql)


 

by :nohypo

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值