开篇介绍

记得笔者在 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 透视操作的更多相关文章

  1. 微软BI 之SSAS 系列 - 在SQL Server 2012 中开发 Analysis Services Multidimensional Project

    SQL Server 2012 中提供了开发 SSAS 项目的两种模型,一种是新增加的 Tabular Model 表格模型,另一种就是原始的 Multidimensional Model 多维模型. ...

  2. 微软BI 之SSAS 系列 - 在 SQL Server 2012 下查看 SSAS 分析服务的模型以及几个模型的简单介绍

    在SSDT中部署一个 SSAS 项目到本地服务器上出现错误. You cannot deploy the model because the localhost deployment server i ...

  3. 微软BI 之SSRS 系列 - 如何在 MDX 查询中获取有效的 MEMBER 成员属性作为参数传递

    这篇小文章的来源是 天善问答,比如在报表中要根据点击某一个成员名称然后作为参数传递给自身报表或者下一张报表,这个在普通的 SQL 查询中没有任何问题.但是在 MDX 中查询是有区别的,比如在 MDX ...

  4. 【HANA系列】SAP HANA SQL取表中每行最小值

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[HANA系列]SAP HANA SQL取表中每 ...

  5. sql中的行转列和列转行的问题

    sql中的行转列和列转行的问题 这是一个常见的问题,也是一个考的问题 1.行转列的问题  简单实例 CREATE TABLE #T ( MON1 INT, MON2 INT, MON3 INT ) G ...

  6. SQL将一个表中的某一列值全部插入到另一个表中

    1.  SQL将一个表中的某一列值全部插入到另一个表中 插入的话: insert into a(col) select col from b; 更新的话: update a set col=selec ...

  7. 在论坛中出现的比较难的sql问题:42(动态行转列 考勤时间动态列)

    原文:在论坛中出现的比较难的sql问题:42(动态行转列 考勤时间动态列) 所以,觉得有必要记录下来,这样以后再次碰到这类问题,也能从中获取解答的思路.

  8. 在论坛中出现的比较难的sql问题:39(动态行转列 动态日期列问题)

    原文:在论坛中出现的比较难的sql问题:39(动态行转列 动态日期列问题) 最近,在论坛中,遇到了不少比较难的sql问题,虽然自己都能解决,但发现过几天后,就记不起来了,也忘记解决的方法了. 所以,觉 ...

  9. 在论坛中出现的比较难的sql问题:37(动态行转列 某一行数据转为列名)

    原文:在论坛中出现的比较难的sql问题:37(动态行转列 某一行数据转为列名) 所以,觉得有必要记录下来,这样以后再次碰到这类问题,也能从中获取解答的思路.

随机推荐

  1. QuerySet转化为JSON

    import json data = json.dumps(list(my_table.objects.all().values())) return HttpResponse(data)

  2. easyui1.32 各种问题汇总

    问题一 场景:tab切换,每个tab里用div放一个dataGrid,默认display:none隐藏,当display:'block'的时候,dataGrid会显示不全,仅显示一条线. 解决方法:切 ...

  3. Apache错误:[error] (OS 10038)在一个非套接字上尝试了一个操作

    Apache错误:[error] (OS 10038)在一个非套接字上尝试了一个操作          博客分类: vb2005xu软件学习 OSApache防火墙PHPWindows  日志如下:[ ...

  4. Unity协程(Coroutine)原理深入剖析

    Unity协程(Coroutine)原理深入剖析 By D.S.Qiu 尊重他人的劳动,支持原创,转载请注明出处:http.dsqiu.iteye.com 其实协程并没有那么复杂,网上很多地方都说是多 ...

  5. 使用__slots__

    [使用__slots__] 参考: 1.http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a0 ...

  6. cocos2d-x 坐标系

    OPenGL坐标系:原点为屏幕左下角 屏幕坐标系:原点在屏幕左上角

  7. iOS真机调试问题-App installation failed,The maximum number of apps for free development profiles has been reached.

    The maximum number of apps for free development profiles has been reached. 源引:http://www.jianshu.com ...

  8. css基本知识框架(转)

    css基本知识框架: 1.css样式表的基本概念 2.样式表基本类型-----1.内嵌样式 2.内联样式3.链入外部样式表4.导入外部?式 3.样式表配置方法 4.字体属性----1.font-fam ...

  9. sd_cms置顶新闻,背景颜色突击显示

    维护之前的一个客户网站,使用的是sd_cms系统,因为好久没有维护了,看到这网站的时候,真不敢相信,自己也曾做出过这样的网站. 客户要求置顶新闻始终在最上面,有背景颜色突击显示. 找到对应的代码,修改 ...

  10. 自己随意写了个简单的依赖jquery的轮播图

    //轮播图 function Switcher(obj){ this.box = $(obj.box); this.width = this.box.width(); this.banner = $( ...