PIVOT(透视转换)和UNPIVOT(逆透视转换)
一、原数据状态

二、手动写透视转换1

三、手动写透视转换2

四、PIVOT(透视转换)和UNPIVOT(逆透视转换)详细使用
- 使用标准SQL进行透视转换和逆视转换
--行列转换
create table #demoOrders
(
id int primary key identity(1,1),
CompanyName nvarchar(50),
ProductID int,
ProductName nvarchar(50)
)
insert into #demoOrders (CompanyName,ProductID,ProductName) values('公司1','','产品1')
insert into #demoOrders (CompanyName,ProductID,ProductName) values('公司1','','产品2')
insert into #demoOrders (CompanyName,ProductID,ProductName) values('公司2','','产品2')
insert into #demoOrders (CompanyName,ProductID,ProductName) values('公司2','','产品3')
insert into #demoOrders (CompanyName,ProductID,ProductName) values('公司3','','产品3')
insert into #demoOrders (CompanyName,ProductID,ProductName) values('公司4','','产品3')
insert into #demoOrders (CompanyName,ProductID,ProductName) values('公司5','','产品4')
insert into #demoOrders (CompanyName,ProductID,ProductName) values('公司6','','产品4')
insert into #demoOrders (CompanyName,ProductID,ProductName) values('公司6','','产品5') select * from #demoOrders

透视转换的标准SQL解决方案以一种非常直接的方式来处理转换过程中涉及的三个阶段:
1、分组阶段用group by 子句实现
2、扩展阶段通过在select子句中为每个目标列指定case表达式来实现,这需要事先知道每个扩展元素的取值,并为每个值指定一个单独的case表达式。
3、聚合阶段通过为每个case表达式的结果应用相关的聚合函数来实现。
解题思维步骤:
1.先找到为行列转换的数据,分组查看数据试试:
select CompanyName,ProductName,count(*) as num from #demoOrders
group by ProductName,CompanyName order by CompanyName

2.分组阶段:用group by 子句以行作为分组条件,获取行数据
select CompanyName
from (
select CompanyName,ProductName,COUNT(*)as num from #demoOrders group by ProductName,CompanyName
) T
group by CompanyName

3.扩展阶段:找到列的数据,为每个目标列指定case表达式;聚合阶段通过为每个case表达式的结果应用相关的聚合函数来实现
select CompanyName,
sum(case when ProductName='产品1' then num else 0 end)[产品1],
sum(case when ProductName='产品2' then num else 0 end)[产品2],
sum(case when ProductName='产品3' then num else 0 end)[产品3],
sum(case when ProductName='产品4' then num else 0 end)[产品4],
sum(case when ProductName='产品5' then num else 0 end)[产品5]
from (
select CompanyName,ProductName,COUNT(*)as num from #demoOrders group by ProductName,CompanyName
) T
group by CompanyName --以下是分页存储过程,看看拼接sql语句字符串和执行的过程,然后把思路打开一下试试
declare @sql nvarchar(1000)
set @sql='select CompanyName,'--开始设置语句
--------动态生成语句begin(开始转成列)-----
select @sql=@sql+'sum(case when ProductName='''+ProductName+''' then num else 0 end)['+ProductName+'],'
from (select distinct top 100 percent ProductName from #demoOrders order by ProductName)a
--------动态生成语句 end--------------------
print @sql
set @sql =left(@sql,len(@sql)-1)+' from (select CompanyName,ProductName,COUNT(*)as num from #demoOrders group by ProductName,CompanyName)a group by CompanyName'
print @sql --打印输出最终执行的SQL
exec(@sql) --执行SQL字符串

逆透视转换的标准SQL解决方案要实现三个逻辑处理阶段:
1、生成副本:根据来源表的每一行生成多个副本(为需要逆透视的每个列生成一个副本);用cross join(交叉联接)来生成每一行的多个副本
2、提取元素
3、删除不相关的交叉
--逆视数据
select CompanyName,
sum(case when ProductName='产品1' then num else 0 end)[产品1],
sum(case when ProductName='产品2' then num else 0 end)[产品2],
sum(case when ProductName='产品3' then num else 0 end)[产品3],
sum(case when ProductName='产品4' then num else 0 end)[产品4],
sum(case when ProductName='产品5' then num else 0 end)[产品5]
into #unpivotDemo
from (
select CompanyName,ProductName,COUNT(*)as num from #demoOrders group by ProductName,CompanyName
) a group by CompanyName
1、在#unpivotDemo表和每行ProductName之间进行交叉联接
select * from #unpivotDemo
cross join
(values('产品1'),('产品2'),('产品3'),('产品4'),('产品5')) as #unpivotDemo2(ProductName)
--或:
select * from #unpivotDemo
cross join
(
select '产品1' as ProductName
union all
select '产品2'
union all
select '产品3'
union all
select '产品4'
union all
select '产品5'
) as #unpivotDemo2

2.1、生成一个数据列,由它返回与当前副本所代表的产品相对应的列值
select *,
case ProductName
when '产品1' then 产品1
when '产品2' then 产品2
when '产品3' then 产品3
when '产品4' then 产品4
when '产品5' then 产品5
end as num
from #unpivotDemo
cross join (values('产品1'),('产品2'),('产品3'),('产品4'),('产品5')) as #unpivotDemo2(ProductName)
--或:
select *,
case ProductName
when '产品1' then 产品1
when '产品2' then 产品2
when '产品3' then 产品3
when '产品4' then 产品4
when '产品5' then 产品5
end as num
from #unpivotDemo
cross join
(
select '产品1' as ProductName
union all
select '产品2'
union all
select '产品3'
union all
select '产品4'
union all
select '产品5'
) as #unpivotDemo2

2.2、提取所需的数据列
select CompanyName,ProductName,
case ProductName
when '产品1' then 产品1
when '产品2' then 产品2
when '产品3' then 产品3
when '产品4' then 产品4
when '产品5' then 产品5
end as num
from #unpivotDemo
cross join (values('产品1'),('产品2'),('产品3'),('产品4'),('产品5')) as #unpivotDemo2(ProductName)
--或:
select CompanyName,ProductName,
case ProductName
when '产品1' then 产品1
when '产品2' then 产品2
when '产品3' then 产品3
when '产品4' then 产品4
when '产品5' then 产品5
end as num
from #unpivotDemo
cross join
(
select '产品1' as ProductName
union all
select '产品2'
union all
select '产品3'
union all
select '产品4'
union all
select '产品5'
) as #unpivotDemo2

3、0值与NULL值代表不相关的交叉,为了删除不相关的交叉,在外部查询中过滤掉0值与NULL值
select * from
(
select CompanyName,ProductName,
case ProductName
when '产品1' then 产品1
when '产品2' then 产品2
when '产品3' then 产品3
when '产品4' then 产品4
when '产品5' then 产品5
end as num
from #unpivotDemo
cross join (values('产品1'),('产品2'),('产品3'),('产品4'),('产品5')) as #unpivotDemo2(ProductName)
) as T
where num is not null and num <> 0
--或:
select * from
(
select CompanyName,ProductName,
case ProductName
when '产品1' then 产品1
when '产品2' then 产品2
when '产品3' then 产品3
when '产品4' then 产品4
when '产品5' then 产品5
end as num
from #unpivotDemo
cross join
(
select '产品1' as ProductName
union all
select '产品2'
union all
select '产品3'
union all
select '产品4'
union all
select '产品5'
) as #unpivotDemo2
) as T
where num is not null and num <> 0

- 使用T-SQL PIVOT透视转换和UNPIVOT逆透视转换
pivot的使用
select CompanyName,[产品1] as 产品1,[产品2] as 产品2,[产品3] as 产品3,[产品4] as 产品4,[产品5] as 产品5
from
(
--表表达式作为pivot输入表,仅仅返回透视中用到的列
select CompanyName,ProductName,count(*) as num from #demoOrders
group by ProductName,CompanyName
) as sourceTable --分组是隐含的,对表中除掉聚合和条件的列进行分组
pivot
(
sum(num) --聚合函数
for ProductName in([产品1],[产品2],[产品3],[产品4],[产品5]) --准备做列名
) as PivotTable
create table #demotable
(
id int primary key identity(1,1),
orderMonth int ,
subTotal decimal(18,2)
)
insert into #demotable (orderMonth,subTotal) values(5,100.00)
insert into #demotable (orderMonth,subTotal) values(6,100.00)
insert into #demotable (orderMonth,subTotal) values(5,200.00)
insert into #demotable (orderMonth,subTotal) values(6,200.00)
insert into #demotable (orderMonth,subTotal) values(7,100.00)
select * from #demotable --方式一
select id,[] as 五月,[] as 六月,[] as 七月
from
#demotable --基础表作为pivot输入表
pivot
(
sum(#demotable.subTotal) for #demotable.orderMonth in([],[],[])
) as PivotTable
--方式二(推荐使用表表达式作为pivot的输入表,不要对基础表进行操作):
select id,[] as 五月,[] as 六月,[] as 七月
from
(
--表表达式作为pivot输入表,仅仅返回透视中用到的列
select id,orderMonth,subTotal from #demotable
) as sourceTable --分组是隐含的,对表中除掉聚合和条件的列进行分组
pivot
(
sum(subTotal) --聚合函数
for orderMonth in([],[],[]) --准备做列名
) as PivotTable
drop table #demotable

unpivot的使用
create table #demotable2
(
id int,
五月 int,
六月 int,
七月 int
)
insert into #demotable2 values (1,100,100,0);
insert into #demotable2 values (2,200,200,200);
insert into #demotable2 values (3,800,0,0);
select * from #demotable2 --执行UNPIVOT
select id,orderMonth,subTotal
FROM
#demotable2
unpivot
(
subTotal for orderMonth in(五月,六月,七月)
)AS UnpivotTable
drop table #demotable2

练习:
create table #testtable
(
id int primary key identity(1,1),
t_year int ,
t_month int,
t_amount decimal(18,1)
) insert into #testtable (t_year,t_month,t_amount) values(1991,1,1.1)
insert into #testtable (t_year,t_month,t_amount) values(1991,2,1.2)
insert into #testtable (t_year,t_month,t_amount) values(1991,3,1.3) insert into #testtable (t_year,t_month,t_amount) values(1992,1,2.1)
insert into #testtable (t_year,t_month,t_amount) values(1992,2,2.2)
insert into #testtable (t_year,t_month,t_amount) values(1992,3,2.3)
--drop table #testtable
select * from #testtable --//想要的结果
--year m1 m2 m3
--1991 1.1 1.2 1.3
--1992 2.1 2.2 2.3 select max(t_year) as [year],max([]) as m1,max([]) as m2,max([]) as m3
from #testtable
pivot
(
max(t_amount) for t_month in([],[],[])
) as PivotTable
group by t_year select t_amount,ColumnName,YearAndMonth
from #testtable
unpivot
(
YearAndMonth for ColumnName in(t_year,t_month)
) as UnpivotTable --行列转换
--解题思维步骤:
--1.先找到为行列转换的数据,查看数据试试:
select t_year,t_month,t_amount from #testtable
--2.找到列的数据
select
(case when t_month=1 then t_amount else 0 end)[m1],
(case when t_month=2 then t_amount else 0 end)[m2],
(case when t_month=3 then t_amount else 0 end)[m3]
from #testtable
--3.以行作为分组条件,获取行数据;两者结合起来,答案:
select t_year,
max(case when t_month=1 then t_amount else 0 end)[m1],
max(case when t_month=2 then t_amount else 0 end)[m2],
max(case when t_month=3 then t_amount else 0 end)[m3]
from #testtable
group by t_year --------------------以下是sql语句字符串和执行的过程------------------------
declare @sql nvarchar(1000)
set @sql='select t_year,'
--------动态生成列 begin--------
select @sql=@sql+'max(case when t_month='+convert(nvarchar(20),t_month)+' then t_amount else 0 end)[m'+str(t_month,1)+'],'
from (select distinct top 100 percent t_month from #testtable order by t_month) T
print @sql
--------动态生成列 end--------
set @sql=left(@sql,len(@sql)-1)+' from #testtable group by t_year'
print @sql
exec(@sql)
PIVOT(透视转换)和UNPIVOT(逆透视转换)的更多相关文章
- UNPIVOT逆透视以及动态逆透视存储过程
前几天一直练习PIVOT透视,还实现了动态透视的存过程<动态透视表>https://www.cnblogs.com/insus/p/10888277.html 今天练习MS SQL Ser ...
- 《BI那点儿事》数据流转换——逆透视转换
逆透视转换将来自单个记录中多个列的值扩展为单个列中具有同样值的多个记录,使得非规范的数据集成为较规范的版本.例如,每个客户在列出客户名的数据集中各占一行,在该行的各列中显示购买的产品和数量.逆透视转换 ...
- T-SQL中的透视和逆透视
透视 今天抽一点时间来看看透视和逆透视语句,简单的说就是行列转换.假设一个销售表中存放着产品号,产品折扣,产品价格三个列,每一种产品号可能有多种折扣,每一种折扣只对应一个产品价格.下面贴出建表语句和插 ...
- T-SQL基础(7) - 透视,逆透视和分组集
透视转换: use tempdb;if object_id('dbo.Orders', 'U') is not null drop table dbo.Orders;create table dbo. ...
- SQL点滴19—T-SQL中的透视和逆透视
原文:SQL点滴19-T-SQL中的透视和逆透视 透视 今天抽一点时间来看看透视和逆透视语句,简单的说就是行列转换.假设一个销售表中存放着产品号,产品折扣,产品价格三个列,每一种产品号可能有多种折扣, ...
- SQL SERVER技术内幕之7 透视与逆透视
1.透视转换 透视数据(pivoting)是一种把数据从行的状态旋转为列的状态的处理,在这个过程中可能须要对值进行聚合. 每个透视转换将涉及三个逻辑处理阶段,每个阶段都有相关的元素:分组阶段处理相关的 ...
- T-SQL——数据透视和逆透视
目录 0. 测试数据集及说明 0.1 准备测试数据 0.2 对一维表和二维表理解 1. 透视转换 1.1 使用标准SQL进行数据透视 1.2 使用T-SQL中pivot函数进行数据透视 1.3 关于 ...
- SQL Server进阶(八)查询——开窗函数、四大排名函数、透视数据、逆透视数据
概述 ROW_NUMBER() OVER(PARTITION BY CustId ORDER BY ID DESC) https://www.jb51.net/article/75533.htm 开窗 ...
- .NET泛型03,泛型类型的转换,协变和逆变
协变(Convariant)和逆变(Contravariant)的出现,使数组.委托.泛型类型的隐式转换变得可能. 子类转换成基类,称之为协变:基类转换成子类,称之为逆变..NET4.0以来,支持了泛 ...
随机推荐
- dispatch_queue_set_specific可重入的gcd
有时候我们很希望知道当前执行的queue是谁,比如UI操作需要放在main queue中执行.如果可以知道当前工作的queue是谁,就可以很方便的指定一段代码操作在特定的queue中执行.这种做法让G ...
- django基础-01:软件框架,MVC框架,MVT
1. 软件框架 一个公司是由公司中的各部部门来组成的,每一个部门拥有特定的职能,部门与部门之间通过相互的配合来完成让公司运转起来. 一个软件框架是由其中各个软件模块组成的,每一个模块都有特定的功能,模 ...
- HIVE简单操作
1.hive命令登录HIVE数据库后,执行show databases;命令可以看到hive数据库中有一个默认的default数据库. [root@hadoop hive]# hive Logging ...
- Kinect2.0点云数据获取
接上一篇:Kinect2.0获取数据 http://blog.csdn.net/jiaojialulu/article/details/53087988 博主好细心,代码基本上帖过来就可以用,注释掉的 ...
- C 语言循环结构
25.有如下程序 main() { int i,sum; for(i=1;i<=3;sum++) sum+=i; printf("%d\n",sum); } 该程序的执行 ...
- 软RAID管理命令mdadm详解
软RAID管理命令mdadm详解 mdadm是linux下用于创建和管理软件RAID的命令,是一个模式化命令.但由于现在服务器一般都带有RAID阵列卡,并且RAID阵列卡也很廉价,且由于软件RAID的 ...
- Please add or free up more resources then turn off safe mode manually.
解决方案:硬盘满了,释放硬盘空间.
- Jmeter-----邮件观察仪
设置邮件观察仪的目的,将测试结果通过邮件的方式发送给相关的人员,可及时获取到当前测试结果情况. 说明: 本人公司使用的为腾讯企业邮箱,因此下面的介绍方式将以腾讯企业邮箱为准来进行描述 必要的设置: 邮 ...
- java基础(一) -语法
基本语法 编写Java程序时,应注意以下几点: 大小写敏感:Java是大小写敏感的,这就意味着标识符Hello与hello是不同的. 类名:对于所有的类来说,类名的首字母应该大写.如果类名由若干单词组 ...
- Selenium基本使用(十二)测试报告生成
报告目录结构 Reporter根目录 | |-------------LOGS | | | ...