T-SQL 语言基础:逆透视转换
概念
-- 把数据从列的转台转为行的状态
-- 涉及查询数据的透视状态,将来自单个记录中多个列的值扩展为单个列中具有相同值的多个记录
-- 也就是把透视表中的每个源行潜在地转换为多个行
示例表继续使用上一篇博客,TempDB dbo.Orders 表。
T-SQL 语言基础:透视转换
SELECT empid, A, B, C, D
INTO dbo.EmpCustOrders
FROM (
SELECT empid, custid, qty
FROM dbo.orders
) D
PIVOT(SUM(qty) FOR custid IN(A, B, C, D)) P
SELECT * FROM dbo.EmpCustOrders
输出:
逆透视转换处理
标准 SQL 实现
使用标准 SQL 进行逆透视转换,有3个处理阶段:
- 生成副本
- 提取元素
- 删除不相关的交叉
– 解决方案:
步骤 1:
-- 根据源表的每一行生成多个副本(为需要逆透视的每个列生成副本)
-- 可以使用笛卡尔积(交叉联接)生成每行的多个副本
SELECT *
FROM dbo.EmpCustOrders
CROSS JOIN (VALUES('A'), ('B'), ('C'), ('D')) AS CUSTS(CUSTID)
-- 每一行来自 dbo.EmpCustOrders 表的数据都与 CUSTS 表中的每个值组合,生成所有可能的行组合。
-- AS CUSTS(CUSTID) 这部分代码的作用是为值构造器创建的虚拟表命名,并命名该表的列。通过 CROSS JOIN,您可以生成两个表的笛卡尔积,得到所有可能的行组合。
输出:
解释:
-- 实际上以上操作,为源表每行生成4个副本
-- SQL Server 2008 之前的版本中, 使用 UNION ALL
SELECT *
FROM dbo.EmpCustOrders
CROSS JOIN ( select ('A') AS custid
UNION ALL SELECT ('B')
UNION ALL SELECT('C')
UNION ALL SELECT('D')) AS CUSTS;
输出:
步骤 2:
-- 生成数据列 qty,由它返回与当前副本所代表客户相对应的列值
-- 当前 custid 的值为 A 时,则 qty 列返回 A 列值
SELECT empid,custid,
CASE custid
when 'A' THEN A
when 'B' THEN B
when 'C' THEN C
when 'D' THEN D
END AS qty
FROM dbo.EmpCustOrders
CROSS JOIN (VALUES('A'), ('B'), ('C'), ('D')) AS CUSTS(CUSTID)
输出:
步骤 3:
-- 过滤 NUL 值
-- 最终完整实现
SELECT * FROM(
SELECT empid,custid,
CASE custid
when 'A' THEN A
when 'B' THEN B
when 'C' THEN C
when 'D' THEN D
END AS qty
FROM dbo.EmpCustOrders
CROSS JOIN (VALUES('A'), ('B'), ('C'), ('D')) AS CUSTS(CUSTID)
) D
where qty IS NOT NULL;
输出:
T-SQL 逆透视转换
使用 T-SQL UNPIVOT 运算符进行逆透视转换
-- 对数据进行逆透视转换时,会为源表中想要进行逆透视的任意列生成两个结果列
-- 示例中, 对源表 A/ B/ C/ D进行逆透视,生成两个结果列 custid 和 qty
-- 前者用于保存源表列的名称,后者用于保存源表列的值
SELECT empid, custid, qty
FROM dbo.EmpCustOrders
UNPIVOT(qty FOR custid IN(A, B, C, D)) U;
-- 经过透视转换后,保存下来的只是操作的所有聚合结果
-- 而逆透视转换后不会丢失任何信息和数据
输出:
总结
逆透视转换功能强大,用于转换和汇总数据。可以高效地创建复杂报告并执行高级数据分析。
引用
- SQL Server Documentation
数据库脚本下载
TSQLFundamentals2008