经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » SQL语言 » 查看文章
SQL Server 使用 Pivot 和 UnPivot 实现行列转换的问题小结
来源:jb51  时间:2022/1/24 12:39:42  对本文有异议

对于行列转换的数据,通常也就是在做报表的时候用的比较多,之前也零零散散的看了一些,今天就来总结一下。

先创建一个用于演示的临时表:

  1. create table #temp
  2. (
  3. 年份 nvarchar(10) null,
  4. 月份 nvarchar(10) null,
  5. 数量 int null
  6. )
  7. insert into #temp(年份,月份,数量)
  8. select '2015','1','5645' union
  9. select '2015','2','1234' union
  10. select '2015','3','7982' union
  11. select '2016','1','6465' union
  12. select '2016','2','7942' union
  13. select '2016','3','8453' union
  14. select '2017','1','4653' union
  15. select '2017','2','1358' union
  16. select '2017','3','7842'
  17. select * from #temp

下面来实现一些需求:

需求一,按年份分组,不同的月份为一列。

  1. -- 按年份分组,不同的月份为一列
  2. select t.年份,
  3. sum(case t.月份 when '1' then t.数量 end) '1月份',
  4. sum(case t.月份 when '2' then t.数量 end) '2月份',
  5. sum(case t.月份 when '3' then t.数量 end) '3月份'
  6. from #temp t
  7. group by t.年份

另外两种方法:

  1. -- 使用左外连接查询
  2. select t.年份,t1.数量 '1月份',t2.数量 '2月份',t3.数量 '3月份' from #temp t
  3. left join (select 年份,数量 from #temp where 月份='1') t1 on t.年份=t1.年份
  4. left join (select 年份,数量 from #temp where 月份='2') t2 on t.年份=t2.年份
  5. left join (select 年份,数量 from #temp where 月份='3') t3 on t.年份=t3.年份
  6. group by t.年份,t1.数量,t2.数量,t3.数量
  7.  
  8. -- 使用自连接查询
  9. select t.年份,t1.数量 '1月份',t2.数量 '2月份',t3.数量 '3月份'
  10. from #temp t,
  11. (select 年份,数量 from #temp where 月份='1') t1,
  12. (select 年份,数量 from #temp where 月份='2') t2,
  13. (select 年份,数量 from #temp where 月份='3') t3
  14. where t.年份=t1.年份 and t.年份=t2.年份 and t.年份=t3.年份
  15. group by t.年份,t1.数量,t2.数量,t3.数量

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

Pivot 语法:

  1. table_source -- 表名称,即数据源
  2.  
  3. PIVOT(
  4.  
  5. 聚合函数(value_column -- value_column 要转换为 列值 的列名
  6.  
  7. FOR pivot_column -- pivot_column 指定要转换的列
  8.  
  9. IN(<column_list>) -- column_list 自定义的目标列名
  10. )

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

  1. create table #temp
  2. (
  3. Name nvarchar(10) null,
  4. Course nvarchar(10) null,
  5. Score int null
  6. )
  7. insert into #temp(Name,Course,Score)
  8. select '小李','语文','88' union
  9. select '小李','数学','79' union
  10. select '小李','英语','85' union
  11. select '小明','语文','79' union
  12. select '小明','数学','89' union
  13. select '小明','英语','87' union
  14. select '小红','语文','84' union
  15. select '小红','数学','76' union
  16. select '小红','英语','92'
  17. select * from #temp
  18. go

  1. select Name 姓名,
  2. max(case Course when '语文' then Score end) 语文,
  3. max(case Course when '数学' then Score end) 数学,
  4. max(case Course when '英语' then Score end) 英语,
  5. sum(Score) 课程总分,
  6. cast(avg(Score) as decimal(18,2)) 课程平均分
  7. from #temp
  8. group by Name

使用 Pivot 进行 行转列:

  1. select a.Name 姓名,a.语文,a.数学,a.英语
  2. from #temp
  3. pivot
  4. (
  5. max(Score) -- 指定作为转换的列的值 的列名
  6. for Course -- 指定要转换的列的列名
  7. in(语文,数学,英语) -- 自定义的目标列名,即要转换列的不同的值作为列
  8. )

  1. select a.Name 姓名,a.语文,a.数学,a.英语,b.SumScore 课程总分,b.AvgScore 课程平均分
  2. from #temp
  3. pivot
  4. (
  5. max(Score) -- 指定作为转换的列的值 的列名
  6. for Course -- 指定要转换的列的列名
  7. in(语文,数学,英语) -- 自定义的目标列名,即要转换列的不同的值作为列
  8. )a,
  9. (
  10. select t.Name,sum(t.Score) SumScore,cast(avg(t.Score) as decimal(18,2)) AvgScore
  11. from #temp t
  12. group by t.Name
  13. )b
  14. where a.Name=b.Name

UnPivot 语法:

  1. table_source -- 表名称,即数据源
  2. UNPIVOT(
  3. value_column -- value_column 要转换为 行值 的列名
  4. FOR pivot_column -- pivot_column 指定要转换为指定的列
  5. IN(<column_list>) -- column_list 目标列名
  6. )
  1. create table #temp
  2. (
  3. Name nvarchar(10) null,
  4. Chinese int null,
  5. Math int null,
  6. English int null
  7. )
  8. insert into #temp(Name,Chinese,Math,English)
  9. select '小李','88','79','85' union
  10. select '小明','79','89','87' union
  11. select '小红','84','76','92'
  12. select * from #temp
  13. go

  1. select t.Name 姓名,t.Course 课程,t.Score 分数 from
  2. (select t.Name,Course='Chinese',Score=Chinese from #temp t
  3. union all
  4. select t.Name,Course='Math',Score=Math from #temp t
  5. union all
  6. select t.Name,Course='English',Score=English from #temp t) t
  7. order by t.Name,t.Course
  1. select t.Name 姓名,t.Course 课程,t.Score 分数 from
  2. (select t.Name,'Chinese' Course,Chinese Score from #temp t
  3. union all
  4. select t.Name,'Math',Math from #temp t
  5. union all
  6. select t.Name,'English',English from #temp t) t
  7. order by t.Name,t.Course

使用 UnPivot 进行 列转行:

  1. select t.Name 姓名,t.Course 课程,t.Score 分数
  2. from #temp
  3. unpivot
  4. (
  5. Score for Course
  6. in(Chinese,Math,English)
  7. )

到此这篇关于SQL Server 使用 Pivot 和 UnPivot 实现行列转换的文章就介绍到这了,更多相关SQL Server行列转换内容请搜索w3xue以前的文章或继续浏览下面的相关文章希望大家以后多多支持w3xue!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号