微软BI 之SSIS 系列 - 在 SQL 和 SSIS 中实现行转列的 PIVOT 透视操作
开篇介绍
记得笔者在 2006年左右刚开始学习 SQL Server 2000 的时候,遇到一个面试题就是行转列,列转行的操作,当时写了很长时间的 SQL 语句最终还是以失败而告终。后来即使能写出来,也是磕磕碰碰的,虽然很能锻炼 SQL 功底,每次都要挣扎一番,溺水的感觉。记得SQL Server 2005 以后就有了 PIVOT 和 UNPIVOT 这两个函数,可以非常方便的实现行转列和列传行的操作,就不再那么挣扎了。后来,在一个 08 项目中,有一位新的女同事在改一个 ETL,发现 SSIS 包中有一个PIVOT 控件不知道怎么用就叫我帮忙。虽然我觉得花点时间还是可以搞定的,但是为了赶回家看一场球赛,找了一个不靠谱的接口就扔下她一个人给跑了。因为项目应该很急,每个人压力其实都很大,不记得是当天晚上就要交付还是第二天要交付。现在想想,很内疚也非常败人品,因为平时大家伙还都比较信任我,但是关键时刻跑了,确实有点不太负责任。今天正好整理到这一部分的笔记就想到了这个疙瘩,山东的那位妹子如果看到了,说声对不起吧!
SSIS 笔记整理到这几个地方,就来总结一下 PIVOT 的使用,如果之前不会用的,看了这篇文章就可以明白了。
测试代码
IF OBJECT_ID('T040_PRODUCT_SALES') IS NOT NULL
DROP TABLE T040_PRODUCT_SALES
GO
CREATE TABLE T040_PRODUCT_SALES
(
ID INT IDENTITY(1,1),
ProductName VARCHAR(20),
SaleMonth INT,
SalesCount INT
)
-- Inserting test data
INSERT INTO T040_PRODUCT_SALES VALUES
('Bicycle',1,1),
('Shoes',2,2),
('Clothes',3,3),
('Books',4,4),
('Medicine',5,5),
('Drinks',6,6),
('Shoes',7,7),
('Books',1,2),
('Bicycle',1,3),
('Medicine',1,4),
('Clothes',1,5),
('Mobile Phone',1,6),
('Books',1,7),
('Medicine',1,8),
('Shoes',1,9),
('Bicycle',2,10)
SELECT ProductName,
SaleMonth,
SUM(SalesCount) AS SalesCount
FROM T040_PRODUCT_SALES
GROUP BY ProductName,
SaleMonth
ORDER BY ProductName,
SaleMonth

我们需要实现的效果是按产品名称,1月,2月,3月,4月,5月,6月 这七个列来显示 SalesCount 的总数。

怎么来实现这种行列转换效果,只要把下面这个点就理解清楚,照着写就可以实现。
/****
SELECT 非透视列,
[透视列 1] AS '列名1',
[透视列 2] AS '列名2',
[透视列 3] AS '列名3'
FROM (
-- 源数据
SELECT 非透视列,
透视列值的来源列,
需要聚合的值
FROM 表
)AS 别名
PIVOT
(
SUM(需要聚合的值)
FOR 透视列值的来源列 IN ([透视列 1],[透视列 2],[透视列 3])
)AS 别名
****/
对照上面的语法,我们弄清楚这些对应关系:
- 非透视列 - 一般是第一列,把效果想出来,ProductName 就是位于第一列,它是非透视列。
- 透视列 - 就是需要由列变为行的那些列,哪些行中的值需要作为列来显示? 1月 - 6月。
- 透视列值的来源列 - 就是 SaleMonth,这列包含了 1月 - 6月的值。
- 需要聚合的值 - 就是 SalesCount。
把这些需求理解了,就直接按照上面的这个语法就可以实现了,没有一点点多余的代码。
SELECT ProductName,
ISNULL([1],0) AS '1',
ISNULL([2],0) AS '2',
ISNULL([3],0) AS '3',
ISNULL([4],0) AS '4',
ISNULL([5],0) AS '5',
ISNULL([6],0) AS '6'
FROM(
SELECT ProductName,
SaleMonth,
SalesCount
FROM T040_PRODUCT_SALES
)AS Sales
PIVOT
(
SUM(SalesCount)
FOR SaleMonth IN([1],[2],[3],[4],[5],[6])
)AS PIVOTBL

SSIS 中 Pivot 的实现
在数据流中添加一个 OLE DB Source 并配置源测试表。

添加一个 Pivot 控件。

对 Pivot 的配置

Pivot Key - 透视列。透视列中的每一个值(去重之后)将会形成一个新的列。
Set Key - 非透视列,需要和透视列一起显示的聚合列。
Pivot Value - Pivot Key 和 Set Key 一起关联的结果值。
之所以要选择 Ignore un-matched pivot key values and report them after DataFlow execution 是因为:
Pivot 转换控件是一个静态的状态控件,它需要清楚的知道在 Pivot Key 中有哪些确定的值,它需要基于这些值来创建相应的输出列。勾选中它并执行一次包之后,就可以在 Progress/中看到唯一的 Pivot Key 列表,我们在设计的阶段就可以通过这些列表上的值来确定最终我们需要创建的列。

比如,确定了只需要 1月份 - 7月份的作为新的输出列,将这些只拷贝到指定的位置中,根据这些透视列来创建物理表中的透视列。

下面是创建之后的列的名称。

这样整个配置就完成了。

执行的时候查看一下数据,基本上反映出了行转列的结构变化。这不过这些数据本身上看上去有一些重复,且没有聚合。

因此我们应该在查询结果先把需要聚合好的内容聚合好,这样在 PIVOT 转换控件中就直接进行行,列转换而不是转换在聚合,这样效率更高一些。

按照 ProductName 和销售月份实现了对数据的行列转换,数据信息的易读性显而易见。

当然也可以看看 Show Advanced Editor 中的内容。

在这里可以看到 Pivot 转换控件之前有 3 个数据源列,在经过 Pivot 转换之后,其 Output Columns 变成 8 列向下输出。

更多 BI 文章请参看 BI 系列随笔列表 (SSIS, SSRS, SSAS, MDX, SQL Server) 如果觉得这篇文章看了对您有帮助,请帮助推荐,以方便他人在 BIWORK 博客推荐栏中快速看到这些文章。
微软BI 之SSIS 系列 - 在 SQL 和 SSIS 中实现行转列的 PIVOT 透视操作的更多相关文章
- 微软BI 之SSAS 系列 - 在SQL Server 2012 中开发 Analysis Services Multidimensional Project
SQL Server 2012 中提供了开发 SSAS 项目的两种模型,一种是新增加的 Tabular Model 表格模型,另一种就是原始的 Multidimensional Model 多维模型. ...
- 微软BI 之SSAS 系列 - 在 SQL Server 2012 下查看 SSAS 分析服务的模型以及几个模型的简单介绍
在SSDT中部署一个 SSAS 项目到本地服务器上出现错误. You cannot deploy the model because the localhost deployment server i ...
- 微软BI 之SSRS 系列 - 如何在 MDX 查询中获取有效的 MEMBER 成员属性作为参数传递
这篇小文章的来源是 天善问答,比如在报表中要根据点击某一个成员名称然后作为参数传递给自身报表或者下一张报表,这个在普通的 SQL 查询中没有任何问题.但是在 MDX 中查询是有区别的,比如在 MDX ...
- 【HANA系列】SAP HANA SQL取表中每行最小值
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[HANA系列]SAP HANA SQL取表中每 ...
- sql中的行转列和列转行的问题
sql中的行转列和列转行的问题 这是一个常见的问题,也是一个考的问题 1.行转列的问题 简单实例 CREATE TABLE #T ( MON1 INT, MON2 INT, MON3 INT ) G ...
- SQL将一个表中的某一列值全部插入到另一个表中
1. SQL将一个表中的某一列值全部插入到另一个表中 插入的话: insert into a(col) select col from b; 更新的话: update a set col=selec ...
- 在论坛中出现的比较难的sql问题:42(动态行转列 考勤时间动态列)
原文:在论坛中出现的比较难的sql问题:42(动态行转列 考勤时间动态列) 所以,觉得有必要记录下来,这样以后再次碰到这类问题,也能从中获取解答的思路.
- 在论坛中出现的比较难的sql问题:39(动态行转列 动态日期列问题)
原文:在论坛中出现的比较难的sql问题:39(动态行转列 动态日期列问题) 最近,在论坛中,遇到了不少比较难的sql问题,虽然自己都能解决,但发现过几天后,就记不起来了,也忘记解决的方法了. 所以,觉 ...
- 在论坛中出现的比较难的sql问题:37(动态行转列 某一行数据转为列名)
原文:在论坛中出现的比较难的sql问题:37(动态行转列 某一行数据转为列名) 所以,觉得有必要记录下来,这样以后再次碰到这类问题,也能从中获取解答的思路.
随机推荐
- 使用imap协议接收邮件
之前一直使用PHPMail类进行发送邮件,这个是一个非常强大的类,但是其实底层就是使用mail()函数来进行发送的. 但是现在公司有个需求是 写个程序需要实时的接收邮件,主要是判断邮件发出去了,并且 ...
- XidianOJ 1182 Chinese Paladin – Qi’s troubles
题目描述 As we all know, Xiahou Jinxuan (Chinese Paladin 5 Prequel's protagonist) and Yue Jinzhao (Chine ...
- angularjs发送delete请求传参数的方法
angularjs使用$http.delete()发送请求,默认是没法通过变量来传参数
- python学习笔记1-元类__metaclass__
type 其实就是元类,type 是python 背后创建所有对象的元类 python 中的类的创建规则: 假设创建Foo 这个类 class Foo(Bar): def __init__(): ...
- 国内外著名B2C系统介绍兼比较ASP.NET和PHP
国内外著名B2C系统介绍兼比较ASP.NET和PHP 2010-06-08 11:44 来源: 我来投稿 我要评论 中介交易 SEO诊断淘宝客 站长团购 云主机 A5外包 国内外著名 ...
- Volley框架之网络请求和图片加载
Volley是 Google 推出的 Android 异步网络请求框架和图片加载框架. Volley的特性 (1).封装了的异步的请求API.Volley 中大多是基于接口的设计,可配置性强.(2). ...
- Collection List Set和Map用法与区别
labels:Collection List Set和Map用法与区别 java 散列表 集合 Collection 接 口的接口 对 象的集合 ├ List ...
- 实现公告栏无缝滚动的js代码(转)
<!DOCTYPE HTML> <html> <head> <meta charset="gb2312" /> <title& ...
- TNetHTTPClient演示
TNetHTTPClient演示 TNetHTTPClient是DELPHI新增加的异步HTTP通信控件(区别于INDY的阻塞控件). unit Unit1; interface uses Winap ...
- centos上手动编译安装tmux的问题
https://blog.linuxeye.com/323.html 装个tmux也是不容易.. 关键词:libevent要自己下载2.0版,然后编译.安装时还要各种参数指定目录.