开篇介绍

记得笔者在 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. delphi 10 seattle 安卓服务开发(二)

    关于delphi 10 移动服务开发的几张图

  2. 线程池的使用ExecutorService

    private ExecutorService executorService = Executors.newFixedThreadPool(5); // 引入线程池来管理多线程 private vo ...

  3. MySQL计算销售员昨日各指标综合得分_20161206

    数据需求如上,新增重激活以15天未下单为界定 SELECT d.销售员,(日销售额得分*0.6+日新增客户数得分*0.15+日客单价得分*0.1+日客户平均产品数得分*0.15)AS 综合得分,日销售 ...

  4. sublime好看的主题webstrom破解

    http://equinusocio.github.io/material-theme/ sublime jsDoc注释 Doc Blockr webstrom破解 http://15.idea.la ...

  5. mac 安装Homebrew

    ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

  6. C++ JsonCpp 使用(含源码下载)

    C++ JsonCpp 使用(含源码下载) 前言 JSON是一个轻量级的数据定义格式,比起XML易学易用,而扩展功能不比XML差多少,用之进行数据交换是一个很好的选择JSON的全称为:JavaScri ...

  7. linux 驱动学习笔记02--应用实例:在内核中新增驱动代码目录和子目录

    下面来看一个综合实例,假设我们要在内核源代码 drivers 目录下为 ARM 体系结构新增如下用于 test driver 的树型目录:| --test  | -- cpu  | -- cpu.c ...

  8. OA 办公自动化系统:权限管理模块的实现原理思路

    OA系统分有许多的模块,如系统管理模块.等一些比较高级的业务操作.此类业务是不允许让普通员工来操作的,思路如下: 给系统添加角色表,每个用户对应一个角色,每个角色可以拥有多个权限, 如下:创建权限表( ...

  9. jdk代理和cglib代理

    1.jdk静态代理(静态代理和动态代理) 本质:在内存中构建出接口的实现类. 缺陷:只能对实现接口的类实现动态代理, 使用cglib可以对没有实现接口的类进行动态代理. 2.cglib动态代理     ...

  10. java代码性能优化总结(转载)

    原文链接:http://developer.51cto.com/art/201511/496263.htm 前言 代码优化,一个很重要的课题.可能有些人觉得没用,一些细小的地方有什么好修改的,改与不改 ...