1、行轉列
---1、最簡單的行轉列
/*
問題:假設有張學生成績表(tb)如下:
姓名課程分數
張三語文74
張三數學83
張三物理93
李四語文74
李四數學84
李四物理94
想變成(得到如下結果):
姓名語文數學物理
李四74 84 94
張三74 83 93
*/
--測試用
IF OBJECT_ID('[tb]')IS NOT NULL DROP TABLE[tb]
GO
create tabletb(姓名varchar(10), 課程 varchar(10), 分數 int)
insert intotb values('張三', '語文', 74)
insert intotb values('張三', '數學', 83)
insert intotb values('張三', '物理', 93)
insert intotb values('李四', '語文', 74)
insert intotb values('李四', '數學', 84)
insert intotb values('李四', '物理', 94)
go
--SQL SERVER2000 動態SQL,指課程不止語文、數學、物理這三門課程。(以下同)
declare @sql varchar(8000)
set @sql= 'select 姓名'
select @sql= @sql + ' , max(case 課程when'''+ 課程 + ''' then 分數else0 end) ['+ 課程 + ']'
from (selectdistinct 課程 from tb)asa
set @sql= @sql + ' from tb group by 姓名'
exec(@sql)
--通過動態構建@sql,得到如下腳本
select 姓名as 姓名 ,
max(case課程 when '語文' then 分數 else 0end)語文,
max(case課程 when '數學' then 分數 else 0end)數學,
max(case課程 when '物理' then 分數 else 0end)物理
from tb
group by姓名
--SQL SERVER2005 動態SQL。
declare @sql varchar(8000)
select @sql= isnull(@sql+ '],[' , '') + 課程 from tb groupby課程
set @sql= '[' + @sql + ']'
exec ('select * from (select * from tb) a pivot (max(分數)for課程in (' + @sql + ')) b')
--得到SQLSERVER 2005靜態SQL。
select *from (select* from tb) a pivot(max(分數)for 課程 in(語文,數學,物理))b
--查詢結果
/*
姓名 數學 物理 語文
--------------------- ----------- -----------
李四 84 94 74
張三 83 93 74
(所影響的行數爲2行)
*/
--2 加合計
/*
問題:在上述結果的基礎上加平均分,總分,得到如下結果:
姓名語文數學物理平均分總分
---- ---- -------- ------ ----
李四74 84 94 84.00 252
張三74 83 93 83.33 250
*/
--SQL SERVER2000 靜態SQL。
select 姓名姓名,
max(case課程 when '語文' then 分數 else 0end)語文,
max(case課程 when '數學' then 分數 else 0end)數學,
max(case課程 when '物理' then 分數 else 0end)物理,
cast(avg(分數*1.0)as decimal(18,2))平均分,
sum(分數)總分
from tb
group by姓名
--SQL SERVER2000 動態SQL。
declare @sql varchar(8000)
set @sql= 'select 姓名'
select @sql= @sql + ' , max(case 課程when'''+ 課程 + ''' then 分數else0 end) ['+ 課程 + ']'
from (selectdistinct 課程 from tb)asa
set @sql= @sql + ' , cast(avg(分數*1.0)as decimal(18,2))平均分, sum(分數)總分from tb group by 姓名'
exec(@sql)
--SQL SERVER2005 靜態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 groupby姓名) n
where m.姓名= n.姓名
--SQL SERVER2005 動態SQL。
declare @sql varchar(8000)
select @sql= isnull(@sql+ ',' , '') + 課程 from tb groupby課程
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(分數)總分fromtb group by 姓名) n
where m.姓名= n.姓名')
其他實例
http://topic.csdn.net/u/20100708/18/55df5a90-27a7-4452-a69a-27f735539a1f.html?seed=24842417&r=66831902#r_66831902
--3、不同數據按照序號轉爲列,方法基本同1
if object_id('tb1')is not null drop tabletb1
go
CREATE tabletb1 --數據表
(
cpici varchar(10)not null,
cname varchar(10)not null,
cvalue intnull
)
--插入測試數據
INSERT INTOtb1 values('T501','x1',31)
INSERT INTOtb1 values('T501','x1',33)
INSERT INTOtb1 values('T501','x1',5)
INSERT INTOtb1 values('T502','x1',3)
INSERT INTOtb1 values('T502','x1',22)
INSERT INTOtb1 values('T502','x1',3)
INSERT INTOtb1 values('T503','x1',53)
INSERT INTOtb1 values('T503','x1',44)
INSERT INTOtb1 values('T503','x1',50)
INSERT INTOtb1 values('T503','x1',23)
--在sqlserver2000裏需要用自增輔助
alter tabletb1 add id int identity
go
declare @s varchar(8000)
set @s='select cpici '
select @s=@s+',max(case when rn='+ltrim(rn)+' then cvalue end) ascvlue'+ltrim(rn)
from (selectdistinct rn from (selectrn=(selectcount(1)from tb1 where cpici=t.cpiciand id<=t.id)from tb1 t)a)t
set @s=@s+' from (select rn=(selectcount(1) from tb1 where cpici=t.cpici and id<=t.id),* from tb1 t
) t group bycpici'
exec(@s)
go
alter tabletb1 drop column id
--再就可以用row_number
declare @s varchar(8000)
set @s='select cpici '
select @s=@s+',max(case when rn='+ltrim(rn)+' then cvalue end) ascvlue'+ltrim(rn)
from (selectdistinct rn from (selectrn=row_number()over(partitionby cpici order by getdate())from tb1)a)t
set @s=@s+' from (selectrn=row_number()over(partition by cpici order by getdate()),* from tb1
) t group bycpici'
exec(@s)
---結果
/*
cpici cvlue1 cvlue2 cvlue3 cvlue4
--------------------- ----------- ----------- -----------
T501 31 33 5 NULL
T502 3 22 3 NULL
T503 53 44 50 23
警告: 聚合或其他SET 操作消除了空值。
(3 行受影響)
*/
--測試用
IF OBJECT_ID('[tb]')IS NOT NULL DROP TABLE[tb]
GO
create tabletb(電話號碼varchar(15),通話時長 int ,行業 varchar(10))
insert tb
select '13883633601', 10,'餐飲'union all
select '18689704236', 20,'物流'union all
select '13883633601', 20,'物流'union all
select '13883633601', 20,'汽車'union all
select '18689704236', 20,'醫療'union all
select '18689704236', 20,'it' union all
select '18689704236', 20,'汽車'union all
select '13883633601', 50,'餐飲'
go
declare @sql varchar(8000)
set @sql='select電話號碼,sum(通話時長)通話總和'
select @sql=@sql+',max(case when rowid='+ltrim(rowid)+' then 行業else'''' end) as [行業'+ltrim(rowid)+']'
from (selectdistinct rowid from (select (select count(distinct行業) from tb where電話號碼=t.電話號碼and 行業<=t.行業)rowid
from tbt) a) b
set @sql=@sql+' from ( select * , (selectcount(distinct行業) from tb where 電話號碼=t.電話號碼and行業<=t.行業)rowid
from tb t ) tgroup by 電話號碼'
exec(@sql)
--結果
/*
(所影響的行數爲8行)
電話號碼 通話總和 行業 行業 行業 行業
-------------------------- ---------- ---------- ---------- ----------
13883633601 100 餐飲 汽車 物流
18689704236 80 it 汽車 物流 醫療
(所影響的行數爲2行)
*/
另一種動態行轉列:
http://topic.csdn.net/u/20100612/10/4CFCB667-89FA-4985-90D5-B8A420A6FF12.html
if object_id('[tb]')is not null drop table[tb]
go
create table[tb]([姓名]varchar(1),[部門]varchar(4),[學歷]varchar(4),[出生年月]datetime)
insert [tb]
select 'A','後勤','高中','1986-1-1'union all
select 'B','後勤','初中','1984-3-7'union all
select 'C','管理','本科','1987-2-1'union all
select 'D','操作','專科','1976-2-1'union all
select 'E','操作','專科','1943-2-1'
go
GO
if object_id('GetGroupByCol')is not null drop procGetGroupByCol
go
create PROCEDURE [dbo].[GetGroupByCol]
@colm nvarchar(100)
AS
declare @sql varchar(4000)
set @sql='
declare @sqlvarchar(8000)
set@sql=''select 部門''
select @sql=@sql+ '', sum(case ltrim('+@colm+')when ''''''+ltrim('+@colm + ')+'''''' then 1 else 0 end)
[''+ltrim(' + @colm + ')+'']'' from (select distinct '+@colm+' from tb where '+@colm+' is not null) as a
set @sql = @sql+ '' from tb group by 部門''
exec(@sql)'
exec(@sql)
GO
exec GetGroupByColN'學歷'
exec GetGroupByColN'出生年月'
exec GetGroupByColN'姓名'
/*
(所影響的行數爲5行)
部門 本科 初中 高中 專科
--------------- ----------- ----------- -----------
操作 0 0 0 2
管理 1 0 0 0
後勤 0 1 1 0
(所影響的行數爲3行)
部門 02 1 1943 12:00AM 02 1 1976 12:00AM 03 7 1984 12:00AM 01 1 1986 12:00AM 02 1 1987 12:00AM
---------------------- ------------------ ------------------ ------------------------------------
操作 1 1 0 0 0
管理 0 0 0 0 1
後勤 0 0 1 1 0
(所影響的行數爲3行)
部門 A B C D E
--------------- ----------- ----------- ----------- -----------
操作 0 0 0 1 1
管理 0 0 1 0 0
後勤 1 1 0 0 0
(所影響的行數爲3行)
*/