当前位置: 首页 > news >正文

SQL Server 使用 Pivot 和 UnPivot 实现行列转换

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

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

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

下面来实现一些需求:

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

-- 按年份分组,不同的月份为一列
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.年份

另外两种方法:

-- 使用左外连接查询
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.数量

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

 

Pivot 语法:

table_source    -- 表名称,即数据源

    PIVOT(

    聚合函数(value_column)    -- value_column 要转换为 列值 的列名

    FOR pivot_column        -- pivot_column 指定要转换的列

    IN(<column_list>)        -- 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

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

使用 Pivot 进行 行转列:

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

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

 

UnPivot 语法:

table_source    -- 表名称,即数据源

    UNPIVOT(

    value_column    -- value_column 要转换为 行值 的列名

    FOR pivot_column    -- pivot_column 指定要转换为指定的列

    IN(<column_list>)    -- 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

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

使用 UnPivot 进行 列转行:

select t.Name 姓名,t.Course 课程,t.Score 分数 
from #temp 
unpivot 
(
    Score for Course
    in(Chinese,Math,English)
)t

 

转载于:https://www.cnblogs.com/Brambling/p/6759992.html

相关文章:

  • 博通孔海泉:一个完全无线连接的市场要解决4个问题
  • CCF NOI1048 检测矩阵
  • IndexedDB
  • pl/sql 笔记之存储过程、函数、包、触发器(下)
  • mysql的库和表相关操作
  • Exchange 2010升级sp2报错
  • 【Cocosd2d-x CCMenu菜单之二】
  • ISO8583开发注意事项和心得体会
  • iOS 相册和网络图片的存取
  • beanshell获取响应结果数据
  • XYGame-网络同步3-防作弊
  • 红黑树 - C++代码实现
  • 自己定义iOS上双击Home键图切换
  • 数据预测的步骤
  • Elasticsearch学习笔记-04.2删除文档
  • 【RocksDB】TransactionDB源码分析
  • CentOS7简单部署NFS
  • Java 网络编程(2):UDP 的使用
  • Python学习之路16-使用API
  • Vue.js源码(2):初探List Rendering
  • 检测对象或数组
  • 经典排序算法及其 Java 实现
  • 利用DataURL技术在网页上显示图片
  • 前端 CSS : 5# 纯 CSS 实现24小时超市
  • 入口文件开始,分析Vue源码实现
  • 双管齐下,VMware的容器新战略
  • 无服务器化是企业 IT 架构的未来吗?
  • 详解NodeJs流之一
  • Spring Batch JSON 支持
  • 不要一棍子打翻所有黑盒模型,其实可以让它们发挥作用 ...
  • ​草莓熊python turtle绘图代码(玫瑰花版)附源代码
  • ​你们这样子,耽误我的工作进度怎么办?
  • (2)STM32单片机上位机
  • (C语言)编写程序将一个4×4的数组进行顺时针旋转90度后输出。
  • (Git) gitignore基础使用
  • (Java实习生)每日10道面试题打卡——JavaWeb篇
  • (Redis使用系列) Springboot 使用Redis+Session实现Session共享 ,简单的单点登录 五
  • (附源码)springboot青少年公共卫生教育平台 毕业设计 643214
  • (附源码)计算机毕业设计SSM在线影视购票系统
  • (三)elasticsearch 源码之启动流程分析
  • (十二)python网络爬虫(理论+实战)——实战:使用BeautfulSoup解析baidu热搜新闻数据
  • (终章)[图像识别]13.OpenCV案例 自定义训练集分类器物体检测
  • (转)负载均衡,回话保持,cookie
  • ****Linux下Mysql的安装和配置
  • .NET连接数据库方式
  • .NET中的Event与Delegates,从Publisher到Subscriber的衔接!
  • .net中的Queue和Stack
  • @angular/cli项目构建--http(2)
  • [ActionScript][AS3]小小笔记
  • [ChromeApp]指南!让你的谷歌浏览器好用十倍!
  • [Java][算法 双指针]Day 02---LeetCode 热题 100---04~07
  • [jQuery]div滚动条回到最底部
  • [LeetCode] Minimum Path Sum
  • [nlp] id2str的vocab.json转换为str2id
  • [nlp] 多语言大模型不同语种/语系数据的数据配比调节