关闭

SQL行转列问题总结(pivot的使用)

5079人阅读 评论(0) 收藏 举报
分类:

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

*/

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:123553次
    • 积分:1648
    • 等级:
    • 排名:千里之外
    • 原创:52篇
    • 转载:9篇
    • 译文:0篇
    • 评论:4条
    最新评论