SQL行轉列問題總結(pivot的使用)

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行)

*/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章