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

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

  1. create table #temp
  2. (
  3. 年份 nvarchar(10) null,
  4. 月份 nvarchar(10) null,
  5. 数量 int null
  6. )
  7.  
  8. insert into #temp(年份,月份,数量)
  9. select '','','' union
  10. select '','','' union
  11. select '','','' union
  12. select '','','' union
  13. select '','','' union
  14. select '','','' union
  15. select '','','' union
  16. select '','','' union
  17. select '','',''
  18.  
  19. select * from #temp

下面来实现一些需求:

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

  1. -- 按年份分组,不同的月份为一列
  2. select t.年份,
  3. sum(case t.月份 when '' then t.数量 end) '1月份',
  4. sum(case t.月份 when '' then t.数量 end) '2月份',
  5. sum(case t.月份 when '' 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 月份='') t1 on t.年份=t1.年份
  4. left join (select 年份,数量 from #temp where 月份='') t2 on t.年份=t2.年份
  5. left join (select 年份,数量 from #temp where 月份='') 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 月份='') t1,
  12. (select 年份,数量 from #temp where 月份='') t2,
  13. (select 年份,数量 from #temp where 月份='') 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.  
  8. insert into #temp(Name,Course,Score)
  9. select '小李','语文','' union
  10. select '小李','数学','' union
  11. select '小李','英语','' union
  12. select '小明','语文','' union
  13. select '小明','数学','' union
  14. select '小明','英语','' union
  15. select '小红','语文','' union
  16. select '小红','数学','' union
  17. select '小红','英语',''
  18.  
  19. select * from #temp
  20. 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. )a

  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.  
  3. UNPIVOT(
  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. Chinese int null,
  5. Math int null,
  6. English int null
  7. )
  8.  
  9. insert into #temp(Name,Chinese,Math,English)
  10. select '小李','','','' union
  11. select '小明','','','' union
  12. select '小红','','',''
  13.  
  14. select * from #temp
  15. 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. )t

SQL Server 使用 Pivot 和 UnPivot 实现行列转换的更多相关文章

  1. SQL server 2005 PIVOT运算符的使用

    原文:SQL server 2005 PIVOT运算符的使用 PIVOT,UNPIVOT运算符是SQL server 2005支持的新功能之一,主要用来实现行到列的转换.本文主要介绍PIVOT运算符的 ...

  2. SQL Server数据库PIVOT函数的使用详解(一)

    http://database.51cto.com/art/201108/285250.htm SQL Server数据库中,PIVOT在帮助中这样描述滴:可以使用 PIVOT 和UNPIVOT 关系 ...

  3. SQL Server里PIVOT运算符的”红颜祸水“

    在今天的文章里我想讨论下SQL Server里一个特别的T-SQL语言结构——自SQL Server 2005引入的PIVOT运算符.我经常引用这个与语言结构是SQL Server里最危险的一个——很 ...

  4. SQL Server将查询出数据进行列转行操作

    在日常的SQL Server数据查询时经常会遇到需要将数据列转换成行的操作,现将自己学习的列转行SQL语句举例如下: --首先查询语句 SELCT * FROM  YXBAK..TBYJKSTEMP ...

  5. SQL Server数据库PIVOT函数的使用详解(二)

    动态的行转列 原理就是 把需要转成列的行拼出来 DECLARE @fieldName VARCHAR(); SET @fieldName=''; SELECT @fieldName = @fieldN ...

  6. 在SQL Server中 获取日期、日期格式转换

    --常用日期转换参数: PRINT CONVERT(varchar, getdate(), 120 ) 2016-07-20 16:09:01 PRINT replace(replace(replac ...

  7. sql server 2005全角与半角字符转换

    CREATE FUNCTION D_ByteExchangeS_Byte(@str NVARCHAR(4000), --要转换的字符串@flag bit              --转换标志,0转换 ...

  8. SQL Server 一些使用小技巧

    1.查询的时候把某一个字段的值拼接成字符串 以下是演示数据. 第一种方式:使用自定义变量 ) SET @Names='' -- 需要先赋值为空字符串,不然结果会是 null SELECT @Names ...

  9. Sql实现行列转换

    从MS Sql Server 2005微软就推出了pivot和unpivot实现行列转换,这极大的方便了我们存储数据和呈现数据.今天就对这两个关键字进行分析,结合实例讲解如何存储数据,如何呈现数据. ...

随机推荐

  1. ubuntu16.04 安装 eclipse

    1. 下载jdk , jdk-8u77-Linux-x64.tar.gz 2.下载 eclipse  , eclipse-jee-mars-2-linux-gtk-x86_64.tar.gz 注:我下 ...

  2. AWS系列-添加购买的https证书

    1.1 自行购买证书 1.2 上传证书 打开EC2的负载均衡 选择相应的ALB 添加侦听器 选择https 端口443 选择目标组 证书类型 上传证书到IAM 证书名称填写申请证书时候的那个域名 私有 ...

  3. MySQL------代码1024,can't get hostname for your address解决方法

    1.hosts文件问题 进入C:\Windows\System32\drivers\etc\hosts 查看里面是否包含: # 127.0.0.1 localhost 没有则添加,再重启MySQL服务 ...

  4. iOS开发之--从URL加载图片

    + (UIImage *) imageFromURLString: (NSString *) urlstring { // This call is synchronous and blocking ...

  5. pushViewController自定义动画http://blog.csdn.net/ralbatr/article/details/22039233

     本文转载至  http://blog.csdn.net/ralbatr/article/details/22039233 实现的主要代码如下: CATransition *transition =  ...

  6. oracle的后台进程能否杀掉

    oracle的后台进程杀掉会有什么影响 说明:本文复制自网友的博客: https://blog.csdn.net/kellyseeme/article/details/8927757 数据库版本为: ...

  7. eclipse控制台不限制显示的行数

    在Preferences中搜索Console,设置Limit console output没有限制即可.

  8. java利用反射机制获取list中的某个字段并以list形式返回

    public static<T> List<Object> listToList(Collection<T> list,String fieldName) thro ...

  9. CodeForces 24A Ring road(dfs)

    A. Ring road time limit per test 2 seconds memory limit per test 256 megabytes input standard input ...

  10. MySQL数据库主从同步延迟分析及解决方案

    一.MySQL的数据库主从复制原理 MySQL主从复制实际上基于二进制日志,原理可以用一张图来表示: 分为四步走: 1. 主库对所有DDL和DML产生的日志写进binlog: 2. 主库生成一个 lo ...