设为首页 收藏本站
查看: 1338|回复: 0

[经验分享] SQL Server 使用 Pivot 和 UnPivot 实现行列转换

[复制链接]

尚未签到

发表于 2017-12-14 13:38:34 | 显示全部楼层 |阅读模式
  对于行列转换的数据,通常也就是在做报表的时候用的比较多,之前也零零散散的看了一些,今天就来总结一下。
  先创建一个用于演示的临时表:
  

create table #temp  
(
  年份   
nvarchar(10)    null,  月份   
nvarchar(10)    null,  数量   
int        null  
)
  

  

insert into #temp(年份,月份,数量)  

select '2015','1','5645' union  
select '2015','2','1234' union
  
select '2015','3','7982' union
  
select '2016','1','6465' union
  
select '2016','2','7942' union
  
select '2016','3','8453' union
  
select '2017','1','4653' union
  
select '2017','2','1358' union
  
select '2017','3','7842'
  

  
select * from #temp
  

DSC0000.png

  下面来实现一些需求:
  需求一,按年份分组,不同的月份为一列。
  

  
select t.年份,
  
sum(case t.月份 when '1' then t.数量 end) '1月份',
  
sum(case t.月份 when '2' then t.数量 end) '2月份',
  
sum(case t.月份 when '3' then t.数量 end) '3月份'
  
from #temp t
  
group by t.年份
  

DSC0001.png

  另外两种方法:
  

  
select t.年份,t1.数量 '1月份',t2.数量 '2月份',t3.数量 '3月份' from #temp t
  
left join (select 年份,数量 from #temp where 月份='1') t1 on t.年份=t1.年份
  
left join (select 年份,数量 from #temp where 月份='2') t2 on t.年份=t2.年份
  
left join (select 年份,数量 from #temp where 月份='3') t3 on t.年份=t3.年份
  
group by t.年份,t1.数量,t2.数量,t3.数量
  

  

  
select t.年份,t1.数量 '1月份',t2.数量 '2月份',t3.数量 '3月份'
  
from #temp t,
  
(select 年份,数量 from #temp where 月份='1') t1,
  
(select 年份,数量 from #temp where 月份='2') t2,
  
(select 年份,数量 from #temp where 月份='3') t3
  
where t.年份=t1.年份 and t.年份=t2.年份 and t.年份=t3.年份
  
group by t.年份,t1.数量,t2.数量,t3.数量
  

DSC0002.png

  返回的结果都是一样的,可以看见这几种方法都是可以实现的(当然,可能还有更多的方法待发掘),不过比起第一种方法,后面这两种方法也太低效了吧,比如一年有12个月份的数据,有个七八年的,那得写多少个子查询、表连接的,而且第一种方法也不是我们想要的。那么就需要用到 Pivot 这种方法了。
  Pivot 语法:
  

table_source  

  PIVOT(
  

  聚合函数(value_column)   
  

  FOR pivot_column        
  

  IN(<column_list>)        
  
)
  

  因为这里列名不允许指定为数字,真是无语。。。我重建了一个数据结构一模一样的表。
  

create table #temp  
(
  Name   
nvarchar(10)    null,  Course   
nvarchar(10)    null,  Score   
int        null  
)
  

  

insert into #temp(Name,Course,Score)  

select '小李','语文','88' union  
select '小李','数学','79' union
  
select '小李','英语','85' union
  
select '小明','语文','79' union
  
select '小明','数学','89' union
  
select '小明','英语','87' union
  
select '小红','语文','84' union
  
select '小红','数学','76' union
  
select '小红','英语','92'
  

  
select * from #temp
  
go
  

DSC0003.png

  

select Name 姓名,  

max(case Course when '语文' then Score end) 语文,  

max(case Course when '数学' then Score end) 数学,  

max(case Course when '英语' then Score end) 英语,  

sum(Score) 课程总分,  

cast(avg(Score) as decimal(18,2)) 课程平均分  

from #temp  
group by Name
  

DSC0004.png

  使用 Pivot 进行 行转列:
  

select a.Name 姓名,a.语文,a.数学,a.英语  

from #temp  
pivot
  
(
max(Score)  for Course        
  in(语文,数学,英语)   
  
)a
  

DSC0005.png

  

select a.Name 姓名,a.语文,a.数学,a.英语,b.SumScore 课程总分,b.AvgScore 课程平均分  

from #temp  
pivot
  
(
max(Score)  for Course        
  in(语文,数学,英语)   
  
)a,
  
(
  select t.Name,sum(t.Score) SumScore,cast(avg(t.Score) as decimal(18,2)) AvgScore
  from #temp t
  group by t.Name
  
)b
  
where a.Name=b.Name
  

DSC0006.png

  UnPivot 语法:
  

table_source  

  UNPIVOT(
  

  value_column   
  

  FOR pivot_column   
  

  IN(<column_list>)   
  
)
  

  

create table #temp  
(
  Name   
nvarchar(10)    null,  Chinese   
int    null,  Math   
int    null,  English
int null  
)
  

  

insert into #temp(Name,Chinese,Math,English)  

select '小李','88','79','85' union  
select '小明','79','89','87' union
  
select '小红','84','76','92'
  

  
select * from #temp
  
go
  

DSC0007.png

  

select t.Name 姓名,t.Course 课程,t.Score 分数 from  
(
select t.Name,Course='Chinese',Score=Chinese from #temp t  

union all  
select t.Name,Course='Math',Score=Math from #temp t
  
union all
  
select t.Name,Course='English',Score=English from #temp t) t
  
order by t.Name,t.Course
  

  

select t.Name 姓名,t.Course 课程,t.Score 分数 from  
(
select t.Name,'Chinese' Course,Chinese Score from #temp t  

union all  
select t.Name,'Math',Math from #temp t
  
union all
  
select t.Name,'English',English from #temp t) t
  
order by t.Name,t.Course
  

DSC0008.png

  使用 UnPivot 进行 列转行:
  

select t.Name 姓名,t.Course 课程,t.Score 分数  

from #temp  
unpivot
  
(
  Score
for Coursein(Chinese,Math,English)  
)t
  

DSC0009.png

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-424018-1-1.html 上篇帖子: 访问内网中的sql server数据库的简便方法 下篇帖子: (provider: 共享内存提供程序, error: 0
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表