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

原文:你真的会玩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(‘20070101‘ AS SMALLDATETIME) AS SQL_VARIANT)),
(2,N‘attr2‘,CAST(CAST(12 AS INT) AS SQL_VARIANT)),
(2,N‘attr3‘,CAST(CAST(‘20090101‘ 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(‘20080101‘ 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
时间: 2024-12-19 07:04:16

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

你真的会玩SQL吗?玩爆你的数据报表之存储过程编写(下)

你真的会玩SQL吗?系列目录 你真的会玩SQL吗?之逻辑查询处理阶段 你真的会玩SQL吗?和平大使 内连接.外连接 你真的会玩SQL吗?三范式.数据完整性 你真的会玩SQL吗?查询指定节点及其所有父节点的方法 你真的会玩SQL吗?让人晕头转向的三值逻辑 你真的会玩SQL吗?EXISTS和IN之间的区别 你真的会玩SQL吗?无处不在的子查询 你真的会玩SQL吗?Case也疯狂 你真的会玩SQL吗?表表达式,排名函数 你真的会玩SQL吗?简单的 数据修改 你真的会玩SQL吗?你所不知道的 数据聚合

你真的会玩SQL吗?数据聚合

本章的内容与 你真的会玩SQL吗?透视转换内容 非常重要,非常重要,非常重要 ,不理解的可以慢慢看,回头看,过几天再看,以后很多思想需要以此为基础而演变. 此后用到的用例数据库是SQL2008里面的,若看过本系列之前的文章,创建过基础样例数据库就不用再创建. 若没有创建过的,用例数据库文件:链接:http://pan.baidu.com/s/1qW1QxA0 密码:dqxx 连续聚合 下面的例子将使用一个EmpOrdersr汇总表,每位雇员在每个月占一行,包含该雇员在一个月内处理过的订单数量,运

你真的会玩SQL吗?Top和Apply

原文:你真的会玩SQL吗?Top和Apply 本章预先想写一些Top和Apply基本的用法,但好像没什么意义,所以删掉了一些无用的东西,只留下几个示例,以保证系列的完整性. Top和Apply解决的常见问题,如返回每个雇员的3个最新订单,订单的时间越新优先级就越高,但还需要引入一个决胜属性,以确定时间桢的订单的优先级,如可用id作为决胜属性.这里提供的解决方案比其它方案要简单得多,且执行速度更快. 返回每个雇员的3个最新订单: SELECT empid , orderid , custid ,

你真的会玩SQL吗?内连接、外连接

原文:你真的会玩SQL吗?内连接.外连接 大多数人一般写多表查询会这样写select * from tbA ,tbB  没有用到JOIN关键字,太Low了,官网标准建议是用JOIN明确表间的关系,下面具体来讲. 连接类型: 交叉联接 得到所连接表的所有组合 (笛卡儿集)cross join 内联接得到连接表的满足条件的记录组合inner join  on 外联接(左.右)得到一个表的所有行,及其余表满 足连接条件的行 full | left | right  outer join  on 交叉联

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

前言 最近要对数据库进行优化,但由于工作项目中已经很少亲自写SQL而且用的都不是很复杂的语句,所以有些生疏了,于是翻翻N年前的笔记资料,想以此来记录回顾总结一些实用的SQL干货让大家来学习,若有不对之处可提出. 记得刚出来行走江湖的时候也是只会增.删.改.查四大法宝,一般公司没有多少复杂的业务,所以就够用了.但后来看着大神会写个几百行的SQL存储过程就感觉自己是不是弱爆了. 如今是大数据的时代,对数据的处理要求越来越重视,要出各种数据报表,因此百万数据处理速度,数据库明显比后台逻辑处理的优势不是

你真的会玩SQL吗?实用函数方汇总

实用函数方法 由于有些知识很少被用到,但真需要用时却忘记了又焦头烂额的到处找. 现在将这些‘冷门“却有效的小知识贡献出来,以备不时之需. 存储过程中的 '''' 相当于数据库中的‘ 单引号 DECLARE @str VARCHAR(100) SET @str='''aaa''' SELECT REPLACE(@str,'''','"') :"aaa" rtrim :使用 LTRIM 删除字符变量中的前导空格 ; RTRIM 删除字符变量中的尾随空格 rtrim(ltrim(s

你真的会玩SQL吗?三值逻辑

先来看一个问题:a not in (b,c,null),返回什么? 是不是有时辛辛苦苦写了个查询,但显示的不是想要的答案?让我们来看看其中的一个陷阱. 我们筛选为某列值为NULL的行,一般会采用如下的方式:select * from tb where col=null 但这无法得到我们想要的结果的,正确的方式是col is null 为什么呢?这就涉及到三值逻辑. 三值逻辑 在SQL中逻辑表达式的可能值包括TRUE.FALSE和UNKNOWN.它们被称之为三值逻辑. 三值逻辑是SQL所特有的.大

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

每次上新功能时都需要添加新表,这时就要涉及到表结构的设计,那就要提到三范式,对于三范式教科书上说得很绕口,那简单点的呢?  三范式 第一范式:属性不可分,不允许存在隐藏字段,属性保持“原子性” 第二范式:要有主键.为实现区分通常需要为表加上一个列,以存储各个实例的唯一标识. 第三范式:要求一个数据库表中不包含已在其它表中已包含的非主关键字信息. 正规化范式(BCDF):所有表中的决定因素必须是一个候选键,如果只有一个候选键,那么就和第三范式是一样的. 第四范式(4NF):消除多值依赖. 第五范式

你真的会玩SQL吗?Case的用法(转)

今天来总结整理一下Case,因为SQL查询中用得最多的逻辑判断. Case具有两种格式.简单Case函数和Case搜索函数. --简单Case函数 CASE sex WHEN '1' THEN '男' WHEN '2' THEN '女' ELSE '其他' END --Case搜索函数 CASE WHEN sex = '1' THEN '男' WHEN sex = '2' THEN '女' ELSE '其他' END 这两种方式,可以实现相同的功能.简单Case函数的写法相对比较简洁,但是和Ca