原文:你真的会玩SQL吗?透视转换

透视转换是一种行列互转的技术,在转过程中可能执行聚合操作,应用非常广泛。

本章与 你真的会玩SQL吗?数据聚合 内容比较重要,还涉及到 你真的会玩SQL吗?Case的用法 的内容,都可以一起看。

下面的例子将使用OpenSchema表,运行创建表:

CREATE TABLE OpenSchema(
objectid INT NOT NULL,
attribute VARCHAR(30) NOT NULL ,
VALUE SQL_VARIANT NOT NULL,
PRIMARY KEY (objectid,attribute)
)
GO INSERT INTO OpenSchema(objectid,attribute,VALUE)
VALUES
(1,N'attr1',CAST(CAST('ABC' AS VARCHAR(10)) AS SQL_VARIANT)),
(1,N'attr2',CAST(CAST(10 AS INT) AS SQL_VARIANT)),
(1,N'attr3',CAST(CAST('' AS SMALLDATETIME) AS SQL_VARIANT)),
(2,N'attr2',CAST(CAST(12 AS INT) AS SQL_VARIANT)),
(2,N'attr3',CAST(CAST('' AS SMALLDATETIME) AS SQL_VARIANT)),
(2,N'attr4',CAST(CAST('Y' AS CHAR(1)) AS SQL_VARIANT)),
(2,N'attr5',CAST(CAST(13.7 AS NUMERIC(9,3)) AS SQL_VARIANT)),
(3,N'attr1',CAST(CAST('xyz' AS VARCHAR(10)) AS SQL_VARIANT)),
(3,N'attr2',CAST(CAST(20 AS INT) AS SQL_VARIANT)),
(3,N'attr3',CAST(CAST('' AS SMALLDATETIME) AS SQL_VARIANT))

将会得到以下输出:

以上VALUE属性保存了多个不同数据类型的值,可以实现要添加新的属性时不用添加列,直接保存。

但是这样查询我们希望把数据旋转为每个属性占一列的传统方式,然后再保存到临时表中处理后续查询称之为透视转换技术。在这里需要回看一下 你真的会玩SQL吗?之逻辑查询处理阶段 对于理解透视转换的步骤是有帮助的。

来看一看经典的行转列实例,如要得到下面的结果怎么做:

透视转换的步骤:

    1. 分组:这里需要为每个对象从多个基础行来创建单独的一列数据,这意味着要对行进行分组,这里依据的是objectid列。
    2. 扩展:从结果列考虑每个唯一的属性都需要一个结果列,对应的是attribute列。这里是attr1,attr2……attr5,列中包含5个表达式。
    3. 聚合:从一组NULL值和已知值中提取出已知值,这就需要使用聚合操作,提取已知值技巧就是使用MAX或MIN函数,这两个会忽略NULL,并返回一个非NULL值,国为只包含一个值的集合最大值和最小值就是这个值。此处对就列是VALUE列。每组中若包含多个非NULL值 ,视情况也可用SUM/AVG。

参考SQL:

SELECT  objectid ,
MAX(CASE WHEN attribute = 'attr1' THEN VALUE
END) AS attr1 ,
MAX(CASE WHEN attribute = 'attr2' THEN VALUE
END) AS attr2 ,
MAX(CASE WHEN attribute = 'attr3' THEN VALUE
END) AS attr3 ,
MAX(CASE WHEN attribute = 'attr4' THEN VALUE
END) AS attr4 ,
MAX(CASE WHEN attribute = 'attr5' THEN VALUE
END) AS attr5
FROM OpenSchema
GROUP BY objectid

这里也可以用PIVOT,不过PIVOT不支持动态透视转换,除了使代码更短外没有什么显著差异,这里就不演示了。

逆透视转换

即列旋转行,常用于规范化数据,如将上面的结果逆转换。

创建表:

CREATE TABLE PvtOpenSchema(
objectid INT NOT NULL,
attr1 VARCHAR(10) NULL ,
attr2 VARCHAR(10) NULL ,
attr3 VARCHAR(10) NULL ,
attr4 VARCHAR(10) NULL ,
attr5 VARCHAR(10) NULL
)

将上面的结果插入此表:

INSERT INTO PvtOpenSchema
(
objectid,attr1,attr2,attr3,attr4,attr5
)
SELECT objectid ,
MAX(CASE WHEN attribute = 'attr1' THEN CAST( VALUE AS VARCHAR(10))
END) AS attr1 ,
MAX(CASE WHEN attribute = 'attr2' THEN CAST( VALUE AS VARCHAR(10))
END) AS attr2 ,
MAX(CASE WHEN attribute = 'attr3' THEN CAST( VALUE AS VARCHAR(10))
END) AS attr3 ,
MAX(CASE WHEN attribute = 'attr4' THEN CAST( VALUE AS VARCHAR(10))
END) AS attr4 ,
MAX(CASE WHEN attribute = 'attr5' THEN CAST( VALUE AS VARCHAR(10))
END) AS attr5
FROM OpenSchema
GROUP BY objectid

结果:

若做到逆转换,将每个objectid 和每个attribute生成结果集中的一行

第一步是为每个甚而行生成5个属性副本,可以通过基础表和每个属性占一行虚拟辅助表执行交叉联接来实现,然后用select 返回objectid和attribute,用case计算值。

可能数据源中会得到与NULL值,如1的attr4,所以还需要对结果进行过滤掉Value为NULL的。

代码如下:

SELECT  objectid ,
attribute ,
VALUE
FROM ( SELECT objectid ,
attribute ,
CASE attribute
WHEN 'attr1' THEN attr1
WHEN 'attr2' THEN attr2
WHEN 'attr3' THEN attr3
WHEN 'attr4' THEN attr4
WHEN 'attr5' THEN attr5
END AS VALUE
FROM PvtOpenSchema
CROSS JOIN ( SELECT 'attr1' AS attribute
UNION ALL
SELECT 'attr2'
UNION ALL
SELECT 'attr3'
UNION ALL
SELECT 'attr4'
UNION ALL
SELECT 'attr5'
) AS attributes
) AS T
WHERE VALUE IS NOT NULL

这里可以使用UNPIVOT表运算符,查询将更简单:

SELECT  objectid ,
attribute ,
VALUE
FROM PvtOpenSchema UNPIVOT ( VALUE FOR attribute IN ( attr1, attr2, attr3, attr4, attr5 ) ) AS a

UNPIVOT会在一个逻辑处理中删除NULL行。

以上只是一个简单的示例,即使现在理解了但在多变的实际应用可能就会迷惘,那时再来对比看看此例。

练习:

           姓名    科目   成绩
张三 语文 80
张三 数学 90
张三 物理 85
李四 语文 85
李四 物理 82
李四 英语 90
李四 政治 70
王五 英语 90

将上表转换为:

           姓名     数学    物理     英语    语文    政治
李四 0 82 90 85 70
王五 0 0 90 0 0
张三 90 85 0 80 0

你真的会玩SQL吗?透视转换的更多相关文章

  1. 你真的会玩SQL吗?透视转换的艺术

    你真的会玩SQL吗?系列目录 你真的会玩SQL吗?之逻辑查询处理阶段 你真的会玩SQL吗?和平大使 内连接.外连接 你真的会玩SQL吗?三范式.数据完整性 你真的会玩SQL吗?查询指定节点及其所有父节 ...

  2. 你真的会玩SQL吗?之逻辑查询处理阶段

    你真的会玩SQL吗?系列目录 你真的会玩SQL吗?之逻辑查询处理阶段 你真的会玩SQL吗?和平大使 内连接.外连接 你真的会玩SQL吗?三范式.数据完整性 你真的会玩SQL吗?查询指定节点及其所有父节 ...

  3. 你真的会玩SQL吗?和平大使 内连接、外连接

    你真的会玩SQL吗?系列目录 你真的会玩SQL吗?之逻辑查询处理阶段 你真的会玩SQL吗?和平大使 内连接.外连接 你真的会玩SQL吗?三范式.数据完整性 你真的会玩SQL吗?查询指定节点及其所有父节 ...

  4. 你真的会玩SQL吗?三范式、数据完整性

    你真的会玩SQL吗?系列目录 你真的会玩SQL吗?之逻辑查询处理阶段 你真的会玩SQL吗?和平大使 内连接.外连接 你真的会玩SQL吗?三范式.数据完整性 你真的会玩SQL吗?查询指定节点及其所有父节 ...

  5. 你真的会玩SQL吗?让人晕头转向的三值逻辑

    你真的会玩SQL吗?系列目录 你真的会玩SQL吗?之逻辑查询处理阶段 你真的会玩SQL吗?和平大使 内连接.外连接 你真的会玩SQL吗?三范式.数据完整性 你真的会玩SQL吗?查询指定节点及其所有父节 ...

  6. 你真的会玩SQL吗?EXISTS和IN之间的区别

    你真的会玩SQL吗?系列目录 你真的会玩SQL吗?之逻辑查询处理阶段 你真的会玩SQL吗?和平大使 内连接.外连接 你真的会玩SQL吗?三范式.数据完整性 你真的会玩SQL吗?查询指定节点及其所有父节 ...

  7. 你真的会玩SQL吗?无处不在的子查询

    你真的会玩SQL吗?系列目录 你真的会玩SQL吗?之逻辑查询处理阶段 你真的会玩SQL吗?和平大使 内连接.外连接 你真的会玩SQL吗?三范式.数据完整性 你真的会玩SQL吗?查询指定节点及其所有父节 ...

  8. 你真的会玩SQL吗?Case也疯狂

    你真的会玩SQL吗?系列目录 你真的会玩SQL吗?之逻辑查询处理阶段 你真的会玩SQL吗?和平大使 内连接.外连接 你真的会玩SQL吗?三范式.数据完整性 你真的会玩SQL吗?查询指定节点及其所有父节 ...

  9. 你真的会玩SQL吗?表表达式,排名函数

    你真的会玩SQL吗?系列目录 你真的会玩SQL吗?之逻辑查询处理阶段 你真的会玩SQL吗?和平大使 内连接.外连接 你真的会玩SQL吗?三范式.数据完整性 你真的会玩SQL吗?查询指定节点及其所有父节 ...

随机推荐

  1. myeclipse中控制台日志比实际晚8小时解决方法及java日志处理

    今天终于忍不住要解决myeclipse控制台中日志显示比实际晚8小时的问题,开始以为myeclipse编辑器时间问题,后来想想不对,myeclipse控制台打印的是tomcat的日志,随后以为是log ...

  2. Linux 挂载光驱

    Linux的硬件设备都在/dev目录下,/dev/cdrom表示光驱,挂载方法如下: 1.挂载光驱 [root@oracle ~]# mount -t iso9660 /dev/cdrom /mnt/ ...

  3. 关于qt学习的一点小记录(1)

    今日为了应付学校作业要求 决定现学qt来制作界面 毕竟c++不像在这方面c#可以那么方便 qt主要依靠信号.槽来实现类似winform中的消息 鉴于要尽快做完,故而没有细看qt 只是大概了解了下界面的 ...

  4. js网页返回页面顶部的小方法

    咳咳,在网页出现滚动条的时候,许多网站会在右下角出现一个图标,点击可以回到页面顶部 本文就记录下js实现代码: 1.在html页面body添加dom元素 <img src="toTop ...

  5. POJ3260:The Fewest Coins(混合背包)

    Description Farmer John has gone to town to buy some farm supplies. Being a very efficient man, he a ...

  6. [Hapi.js] Replying to Requests

    hapi's reply interface is one of it's most powerful features. It's smart enough to detect and serial ...

  7. 【COCOS2DX-对28游戏开发】 Cocos2d-x-3c 道路设计 CocosBase CocosNet CocosWidget

    原文链接:http://blog.csdn.net/cocosviva/article/details/18970717 另一个比較不错的cocos2dx扩展库:https://github.com/ ...

  8. Qt导出Excel的简单实现

    QAxObject对COM对象进行了封装,QAxObject派生自QAxBase,而后者提供了一组API通过IUnknown(不清楚IUnknown的同学可以去看看COM对象模型)指针直接访问COM对 ...

  9. PHP <<EOF EOF的使用方法

    PHP <<EOF EOF的使用方法 <?php     $name = '浅水游';     print <<<EOT             <html& ...

  10. Hacker(十)----常用入侵工具

    黑客若想攻击目标计算机,仅靠DOS命令是无法完成的,还需要一些功能强大的入侵工具,如端口扫描工具.网络嗅探工具.木马制作工具及远程控制工具等. 一.端口扫描工具 端口扫描工具有扫描端口的功能,所谓端口 ...