你真的会玩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吗?之逻辑查询处理阶段 对于理解透视转换的步骤是有帮助的。
来看一看经典的行转列实例,如要得到下面的结果怎么做:

透视转换的步骤:
- 分组:这里需要为每个对象从多个基础行来创建单独的一列数据,这意味着要对行进行分组,这里依据的是objectid列。
- 扩展:从结果列考虑每个唯一的属性都需要一个结果列,对应的是attribute列。这里是attr1,attr2……attr5,列中包含5个表达式。
- 聚合:从一组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吗?透视转换的更多相关文章
- 你真的会玩SQL吗?透视转换的艺术
你真的会玩SQL吗?系列目录 你真的会玩SQL吗?之逻辑查询处理阶段 你真的会玩SQL吗?和平大使 内连接.外连接 你真的会玩SQL吗?三范式.数据完整性 你真的会玩SQL吗?查询指定节点及其所有父节 ...
- 你真的会玩SQL吗?之逻辑查询处理阶段
你真的会玩SQL吗?系列目录 你真的会玩SQL吗?之逻辑查询处理阶段 你真的会玩SQL吗?和平大使 内连接.外连接 你真的会玩SQL吗?三范式.数据完整性 你真的会玩SQL吗?查询指定节点及其所有父节 ...
- 你真的会玩SQL吗?和平大使 内连接、外连接
你真的会玩SQL吗?系列目录 你真的会玩SQL吗?之逻辑查询处理阶段 你真的会玩SQL吗?和平大使 内连接.外连接 你真的会玩SQL吗?三范式.数据完整性 你真的会玩SQL吗?查询指定节点及其所有父节 ...
- 你真的会玩SQL吗?三范式、数据完整性
你真的会玩SQL吗?系列目录 你真的会玩SQL吗?之逻辑查询处理阶段 你真的会玩SQL吗?和平大使 内连接.外连接 你真的会玩SQL吗?三范式.数据完整性 你真的会玩SQL吗?查询指定节点及其所有父节 ...
- 你真的会玩SQL吗?让人晕头转向的三值逻辑
你真的会玩SQL吗?系列目录 你真的会玩SQL吗?之逻辑查询处理阶段 你真的会玩SQL吗?和平大使 内连接.外连接 你真的会玩SQL吗?三范式.数据完整性 你真的会玩SQL吗?查询指定节点及其所有父节 ...
- 你真的会玩SQL吗?EXISTS和IN之间的区别
你真的会玩SQL吗?系列目录 你真的会玩SQL吗?之逻辑查询处理阶段 你真的会玩SQL吗?和平大使 内连接.外连接 你真的会玩SQL吗?三范式.数据完整性 你真的会玩SQL吗?查询指定节点及其所有父节 ...
- 你真的会玩SQL吗?无处不在的子查询
你真的会玩SQL吗?系列目录 你真的会玩SQL吗?之逻辑查询处理阶段 你真的会玩SQL吗?和平大使 内连接.外连接 你真的会玩SQL吗?三范式.数据完整性 你真的会玩SQL吗?查询指定节点及其所有父节 ...
- 你真的会玩SQL吗?Case也疯狂
你真的会玩SQL吗?系列目录 你真的会玩SQL吗?之逻辑查询处理阶段 你真的会玩SQL吗?和平大使 内连接.外连接 你真的会玩SQL吗?三范式.数据完整性 你真的会玩SQL吗?查询指定节点及其所有父节 ...
- 你真的会玩SQL吗?表表达式,排名函数
你真的会玩SQL吗?系列目录 你真的会玩SQL吗?之逻辑查询处理阶段 你真的会玩SQL吗?和平大使 内连接.外连接 你真的会玩SQL吗?三范式.数据完整性 你真的会玩SQL吗?查询指定节点及其所有父节 ...
随机推荐
- myeclipse中控制台日志比实际晚8小时解决方法及java日志处理
今天终于忍不住要解决myeclipse控制台中日志显示比实际晚8小时的问题,开始以为myeclipse编辑器时间问题,后来想想不对,myeclipse控制台打印的是tomcat的日志,随后以为是log ...
- Linux 挂载光驱
Linux的硬件设备都在/dev目录下,/dev/cdrom表示光驱,挂载方法如下: 1.挂载光驱 [root@oracle ~]# mount -t iso9660 /dev/cdrom /mnt/ ...
- 关于qt学习的一点小记录(1)
今日为了应付学校作业要求 决定现学qt来制作界面 毕竟c++不像在这方面c#可以那么方便 qt主要依靠信号.槽来实现类似winform中的消息 鉴于要尽快做完,故而没有细看qt 只是大概了解了下界面的 ...
- js网页返回页面顶部的小方法
咳咳,在网页出现滚动条的时候,许多网站会在右下角出现一个图标,点击可以回到页面顶部 本文就记录下js实现代码: 1.在html页面body添加dom元素 <img src="toTop ...
- POJ3260:The Fewest Coins(混合背包)
Description Farmer John has gone to town to buy some farm supplies. Being a very efficient man, he a ...
- [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 ...
- 【COCOS2DX-对28游戏开发】 Cocos2d-x-3c 道路设计 CocosBase CocosNet CocosWidget
原文链接:http://blog.csdn.net/cocosviva/article/details/18970717 另一个比較不错的cocos2dx扩展库:https://github.com/ ...
- Qt导出Excel的简单实现
QAxObject对COM对象进行了封装,QAxObject派生自QAxBase,而后者提供了一组API通过IUnknown(不清楚IUnknown的同学可以去看看COM对象模型)指针直接访问COM对 ...
- PHP <<EOF EOF的使用方法
PHP <<EOF EOF的使用方法 <?php $name = '浅水游'; print <<<EOT <html& ...
- Hacker(十)----常用入侵工具
黑客若想攻击目标计算机,仅靠DOS命令是无法完成的,还需要一些功能强大的入侵工具,如端口扫描工具.网络嗅探工具.木马制作工具及远程控制工具等. 一.端口扫描工具 端口扫描工具有扫描端口的功能,所谓端口 ...