志铭-2021年10月6日 22:50:00

0. 测试数据集及说明

0.1 准备测试数据

【测试数据1】

WITH Temp1 AS
(
SELECT '张三' AS Name, '语文' AS Subject, 100 AS Scores
UNION ALL
SELECT '张三' AS Name, '数学' AS Subject, 90 AS Scores
UNION ALL
SELECT '张三' AS Name, '英语' AS Subject, 80 AS Scores
UNION ALL
SELECT '李四' AS Name, '语文' AS Subject, 90 AS Scores
UNION ALL
SELECT '李四' AS Name, '数学' AS Subject, 70 AS Scores
UNION ALL
SELECT '李四' AS Name, '英语' AS Subject, 60 AS Scores
)
SELECT * FROM Temp1 结果:
Name Subject Scores
---- ------- -----------
张三 语文 100
张三 数学 90
张三 英语 80
李四 语文 90
李四 数学 70
李四 英语 60

【测试数据2】

WITH Temp2 AS
(
SELECT '张三' AS Name, '八年级二班' AS Class, NULL AS 英语, NULL AS 数学, 100 AS 语文
UNION ALL
SELECT '李四' AS Name, '三年级二班' AS Class, 60 AS 英语, 70 AS 数学, 90 AS 语文
UNION ALL
SELECT '张三' AS Name, '三年级二班' AS Class, 80 AS 英语, 90 AS 数学, NULL AS 语文
)
SELECT * FROM Temp2 结果:
Name Class 英语 数学 语文
---- ---------- ----------- ----------- -----------
张三 八年级二班 NULL NULL 100
李四 三年级二班 60 70 90
张三 三年级二班 80 90 NULL

0.2 对一维表和二维表理解

测试数据1:

  • 称为:一维表
  • 特征:每条记录的特定字段可能出现值重复
  • 一维表是数据记录的最原始的样子。
  • 一维表包含一列字段表示每条记录的属性。比如说测试数据1中的Subject列
  • 一维表的字段名称即表示该字段下的数据的实际含义。比如说测试数据1中的Scores列下的数据表示成绩

测试数据2:

  • 称为:二维表
  • 特征:列字段名称就是种类信息,每条记录的
  • 二维表则是展示出分类汇总后的数据信息
  • 二维表若无说明,是无法明确数据含义的,比如测试数据2,若是不告诉你这是成绩,你是无法理解数据值的真实含义的

一维表和二维表对比:

  • 按照数据库第一范式:一个实体中不应该包含重复类型的特性,对应到表就是:类似的值不能在一个表的多个列上重复

    • 创建表应该按照一维表的格式创建,记录产生信息。
    • 若是建表的时候创建为二维表,将所有的种类做为字段,则可能出现表的字段非常的多,当种类有所添加的时候,后续还要继续添加字段。
  • 一维表方便存储数据,同样也是便于后期查询

  • 二维表可以直观的表现数据的信息,是用于展示的报表和报告


1. 透视转换

1.1 使用标准SQL进行数据透视

--注意这里实现业务场景,在CASE WHEN语句中
--我们应该使用默认的ELSE NULL ,而不是ELSE 0。没有数据是没有数据,0是0
SELECT Name,
SUM(CASE WHEN Subject ='语文' THEN Temp1.Scores ElSE NULL END) AS 语文 ,
SUM(CASE WHEN Subject ='数学' THEN Temp1.Scores ELSE NULL END) AS 数学 ,
SUM(CASE WHEN Subject ='英语' THEN Temp1.Scores ELSE NULL END) AS 英语
FROM Temp1 GROUP BY Temp1.Name 结果:
Name 英语 数学 语文
---- ----------- ----------- -----------
李四 60 70 90
张三 80 90 100

【说明】:使用标准的SQL语句进行数据的透视转换,我们可以直白的发现透视转换,是分为三个阶段的:

分组-->扩展-->聚合

以上例说明:

  • 分组:我们按照Name字段进行分组,使每一个用户产生一条记录

    • 使用GROUP BY实现分组
  • 扩展:扩展是对列的扩展,使用case语句, 对三个科目(语文,数学,英语)扩展为列
    • 使用SELECT 配合CASE WHEN实现
  • 聚合:按照分组依据进行聚合,这里按照Name字段分组,使用SUM函数对Scores字段聚合
    • 使用任一聚合函数聚合

对照上述三个逻辑步骤:

  • Name字段:分组依据字段(分组元素)。指定要用于透视结果表的左侧列,也称为设置键
  • Subject字段:待扩展字段(待扩展元素)。透视结果表中的列头所在的列,也称为透视键,"语文,数学,英语"为目标列的列名的集合,又称为透视输出列
  • Scores字段:聚合字段(聚合元素)。透视结果表中的主要显示的数据就是来自这个字段的值,又称为透视值

1.2 使用T-SQL中pivot函数进行数据透视

【函数】:pivot

【作用】:行转列函数,SQL Server2005

【语法】:pivot(任一聚合函数 for 需转列的值所在列名 in (需转为列名的值))

【用法】:select …from table pivot(……) as T

【示例1】:

现有一张成绩表,表中记录了每个学生每科目的成绩,如下。

现在需要将科目作为列头,统计每个学生的成绩。

WITH Temp1 AS
(
SELECT '张三' AS Name, '语文' AS Subject, 100 AS Scores
UNION ALL
SELECT '张三' AS Name, '数学' AS Subject, 90 AS Scores
UNION ALL
SELECT '张三' AS Name, '英语' AS Subject, 80 AS Scores
UNION ALL
SELECT '李四' AS Name, '语文' AS Subject, 90 AS Scores
UNION ALL
SELECT '李四' AS Name, '数学' AS Subject, 70 AS Scores
UNION ALL
SELECT '李四' AS Name, '英语' AS Subject, 60 AS Scores
)
SELECT T.Name, T.英语, T.数学, T.语文 FROM Temp1 PIVOT(SUM(Scores) FOR [Subject] IN (语文,数学,英语)) T; 结果:
Name 英语 数学 语文
---- ----------- ----------- -----------
李四 60 70 90
张三 80 90 100

【注意1】:

我们是按照以下格式:

select …from table pivot(任意聚合函数(聚合字段) for 待扩展字段名 in (待扩展元素集)) as T

使用pivot对table进行数据透视

若是table中的字段既不是聚合字段,又不是待扩展字段,则会默认为pivot函数中的分组依据的字段。

所以使用pivot函数进行数据透视的结果集一般不会是数据库中的原表,而是一个查询出的特定字段的结果集

【注意2】:

若待扩展元素集是非常规标识符,比如说日期或数字开头的其他类型数据,则我们需要使用方括号将每一个待扩展展元素括起。

【示例2】:

现在在测试数据1中添加一个Class字段,使用pivot函数透视数据

WITH Temp1 AS
(
SELECT '张三' AS Name, '语文' AS Subject, 100 AS Scores,'八年级一班' AS Class
UNION ALL
SELECT '张三' AS Name, '数学' AS Subject, 90 AS Scores,'三年级二班' AS Class
UNION ALL
SELECT '张三' AS Name, '英语' AS Subject, 80 AS Scores,'三年级二班' AS Class
UNION ALL
SELECT '李四' AS Name, '语文' AS Subject, 90 AS Scores,'三年级二班' AS Class
UNION ALL
SELECT '李四' AS Name, '数学' AS Subject, 70 AS Scores,'三年级二班' AS Class
UNION ALL
SELECT '李四' AS Name, '英语' AS Subject, 60 AS Scores,'三年级二班' AS Class
)
SELECT T.Name,T.Class, T.英语, T.数学, T.语文 FROM Temp1 PIVOT(SUM(Scores) FOR [Subject] IN (语文,数学,英语)) T; 结果: Name Class 英语 数学 语文
---- ---------- ----------- ----------- -----------
张三 八年级一班 NULL NULL 100
李四 三年级二班 60 70 90
张三 三年级二班 80 90 NULL

【说明】:结果集Temp1中的class既不是聚合字段,也不是待扩展字段,所以会被默认为是分组依据!

而往往,我们期望的分组依据只要Name字段,

所以一般都是建议不要直接对数据库中的基础表进行透视操作,而是将特定字段查询出来作为一个表结果集,之后在对这个结果集进行透视操作。

1.3 关于 待扩展元素集合获取的方式


2. 逆透视转换

【逆透视】:逆透视转换将来自单个记录中多个列的值扩展为单个列中具有同样值的多个记录,使得非规范的数据集成为较规范的版本。

2.1 使用标准SQL进行数据逆透视

数据的逆透视也是分为三步:请客,斩首,收下当狗

啊唾,不对,应该是是:生成副本-->提取元素-->删除不相干交叉


WITH Temp AS
(
--测试数据集
SELECT '张三' AS Name, '八年级二班' AS Class, NULL AS 英语, NULL AS 数学, 100 AS 语文
UNION ALL
SELECT '李四' AS Name, '三年级二班' AS Class, 60 AS 英语, 70 AS 数学, 90 AS 语文
UNION ALL
SELECT '张三' AS Name, '三年级二班' AS Class, 80 AS 英语, 90 AS 数学, NULL AS 语文
)
,Temp1 AS
(
--为每一行生成副本
--与需要逆透视的列交叉连接获取笛卡尔积
SELECT * FROM Temp CROSS JOIN( VALUES('英语'),('数学'),('语文')) AS T(SubjectName)
--结果
--Name Class 英语 数学 语文 SubjectName
--张三 八年级二班 NULL NULL 100 英语
--张三 八年级二班 NULL NULL 100 数学
--张三 八年级二班 NULL NULL 100 语文
--李四 三年级二班 60 70 90 英语
--李四 三年级二班 60 70 90 数学
--李四 三年级二班 60 70 90 语文
--张三 三年级二班 80 90 NULL 英语
--张三 三年级二班 80 90 NULL 数学
--张三 三年级二班 80 90 NULL 语文
)
,Temp2 AS
(
--当前行SubjectName为英语则取英语列
SELECT Name,Class,Temp1.SubjectName,
CASE Temp1.SubjectName
WHEN '英语' THEN
英语
WHEN '数学' THEN
数学
WHEN '语文' THEN
语文
END AS Scores
FROM Temp1
--结果
--Name Class SubjectName Scores
--张三 八年级二班 英语 NULL
--张三 八年级二班 数学 NULL
--张三 八年级二班 语文 100
--李四 三年级二班 英语 60
--李四 三年级二班 数学 70
--李四 三年级二班 语文 90
--张三 三年级二班 英语 80
--张三 三年级二班 数学 90
--张三 三年级二班 语文 NULL
)
--删除不相关交叉行(排除NULL值行)
SELECT * FROM Temp2 WHERE Temp2.Scores IS NOT NULL --结果
--Name Class SubjectName Scores
--张三 八年级二班 语文 100
--李四 三年级二班 英语 60
--李四 三年级二班 数学 70
--李四 三年级二班 语文 90
--张三 三年级二班 英语 80
--张三 三年级二班 数学 90

2.2 使用T-SQL中unpivot函数进行数据逆透视

【函数】:unpivot

【作用】:列转行函数,SQL Server2005

【语法】:unpivot(作为属性值列的列名 for 属性名 in (同一属性的列名))

【用法】:select …from table unpivot(……) as T

【示例1】


WITH Temp2 AS
(
SELECT '张三' AS Name, '八年级二班' AS Class, NULL AS 英语, NULL AS 数学, 100 AS 语文
UNION ALL
SELECT '李四' AS Name, '三年级二班' AS Class, 60 AS 英语, 70 AS 数学, 90 AS 语文
UNION ALL
SELECT '张三' AS Name, '三年级二班' AS Class, 80 AS 英语, 90 AS 数学, NULL AS 语文
)
SELECT * FROM Temp2 UNPIVOT(Socore FOR Subject IN(英语, 数学, 语文)) T; 结果:
Name Class Socore Subject
---- ---------- -------- ----------
张三 八年级二班 100 语文
李四 三年级二班 60 英语
李四 三年级二班 70 数学
李四 三年级二班 90 语文
张三 三年级二班 80 英语
张三 三年级二班 90 数学

3. 透视之后再逆透视数据信息减少

上面的示例数据中,将原数据(测试数据1)进行透视操作,变为测试数据2。将测试数据2逆透视结果变回了测试数据1。

这只是巧合而已,因为我们的测试数据1中没有出现相同属性(同一个人相同科目)的多条记录:

比如说,如果李四有两条英语成绩如下:

WITH Temp1 AS
(
SELECT '张三' AS Name, '语文' AS Subject, 100 AS Scores
UNION ALL
SELECT '张三' AS Name, '数学' AS Subject, 90 AS Scores
UNION ALL
SELECT '张三' AS Name, '英语' AS Subject, NULL AS Scores--张三英语成绩没有记录
UNION ALL
SELECT '李四' AS Name, '语文' AS Subject, 90 AS Scores
UNION ALL
SELECT '李四' AS Name, '数学' AS Subject, 70 AS Scores
UNION ALL
SELECT '李四' AS Name, '英语' AS Subject, 60 AS Scores--李四有两条英语成绩
UNION ALL
SELECT '李四' AS Name, '英语' AS Subject, 60 AS Scores--李四有两条英语成绩
)
,Temp2 AS --数据透视
(
SELECT * FROM Temp1 PIVOT(SUM(Scores) FOR Subject IN (语文,数学,英语))AS T
)
SELECT * FROM Temp2 UNPIVOT(Scores FOR Subject IN (语文,数学,英语))AS T 透视结果: Name 语文 数学 英语
---- ----------- ----------- -----------
李四 90 70 120
张三 100 90 NULL 对透视结果逆透视: Name Scores Subject
---- ----------- -------------
李四 90 语文
李四 70 数学
李四 120 英语--这里逆透视就无法还原为原始数据(这里就是聚合成一条数据了)
张三 100 语文
张三 90 数学
--张三英语为NULL的记录在原始数据中是存在,而透视再逆透视后则没有了

之前详述了透视包含三个逻辑步骤,分组-->扩展-->聚合。

因为透视包含了聚合,表的信息量减少了,所以在做逆透视无法还原成原始数据。

简单的说:

UNPIVOT 并不完全是 PIVOT 的逆操作。

PIVOT 执行聚合,并将多个可能的行合并为输出中的一行。

UNPIVOT 不重现原始表值表达式的结果,因为行已被合并。

另外,UNPIVOT 输入中的 NULL 值也在输出中消失了。

如果值消失,表明在执行 PIVOT 操作前,输入中可能就已存在原始 NULL 值。


4. 参考

T-SQL——数据透视和逆透视的更多相关文章

  1. SQL点滴19—T-SQL中的透视和逆透视

    原文:SQL点滴19-T-SQL中的透视和逆透视 透视 今天抽一点时间来看看透视和逆透视语句,简单的说就是行列转换.假设一个销售表中存放着产品号,产品折扣,产品价格三个列,每一种产品号可能有多种折扣, ...

  2. SQL SERVER技术内幕之7 透视与逆透视

    1.透视转换 透视数据(pivoting)是一种把数据从行的状态旋转为列的状态的处理,在这个过程中可能须要对值进行聚合. 每个透视转换将涉及三个逻辑处理阶段,每个阶段都有相关的元素:分组阶段处理相关的 ...

  3. T-SQL中的透视和逆透视

    透视 今天抽一点时间来看看透视和逆透视语句,简单的说就是行列转换.假设一个销售表中存放着产品号,产品折扣,产品价格三个列,每一种产品号可能有多种折扣,每一种折扣只对应一个产品价格.下面贴出建表语句和插 ...

  4. T-SQL基础(7) - 透视,逆透视和分组集

    透视转换: use tempdb;if object_id('dbo.Orders', 'U') is not null drop table dbo.Orders;create table dbo. ...

  5. 《BI那点儿事》数据流转换——逆透视转换

    逆透视转换将来自单个记录中多个列的值扩展为单个列中具有同样值的多个记录,使得非规范的数据集成为较规范的版本.例如,每个客户在列出客户名的数据集中各占一行,在该行的各列中显示购买的产品和数量.逆透视转换 ...

  6. SQL Server进阶(八)查询——开窗函数、四大排名函数、透视数据、逆透视数据

    概述 ROW_NUMBER() OVER(PARTITION BY CustId ORDER BY ID DESC) https://www.jb51.net/article/75533.htm 开窗 ...

  7. PIVOT(透视转换)和UNPIVOT(逆透视转换)

    一.原数据状态 二.手动写透视转换1 三.手动写透视转换2 四.PIVOT(透视转换)和UNPIVOT(逆透视转换)详细使用 使用标准SQL进行透视转换和逆视转换 --行列转换 create tabl ...

  8. UNPIVOT逆透视以及动态逆透视存储过程

    前几天一直练习PIVOT透视,还实现了动态透视的存过程<动态透视表>https://www.cnblogs.com/insus/p/10888277.html 今天练习MS SQL Ser ...

  9. 批量处理sql 数据存入xml类型列

    个人记录 需求:当表T1 ItemCode和表T2 ItemName的数据相等时,将表T2所对应的ID和ItemName列的数据分别存入表T1 CAOZUO字段的id元素和text元素的文本中. 下面 ...

随机推荐

  1. ant的javac任务的相关属性配置

    任务和javac命令是相似,它编译两种类型的Java文件1)没有被编译的java文件2)曾经编译过,但是class文件版本和当前对应的java文件版本不匹配的java文件. 1)javac命令支持的参 ...

  2. Java事件模型

    1 import javax.swing.*; 2 import java.awt.event.*; 3 public class TestSourceListener { 4 5 public st ...

  3. 二级C语言题集

    时间:2015-5-13 18:01 在131题之后是按考点分类的题集,有需要的朋友可以看一下 ---------------------------------------------------- ...

  4. Acwing 883高斯消元法的运用

    Acwing 883高斯消元法的运用 解线性方程组 Acwing 883 输入一个包含 n 个方程 n 个未知数的线性方程组. 方程组中的系数为实数. 求解这个方程组. 下图为一个包含 m 个方程 n ...

  5. canvas二次贝塞尔&三次贝塞尔操作实例

    Canvas Quadratic Curve Example canvas = document.getElementById("canvas"); ctx = canvas.ge ...

  6. 30 道 Vue 面试题,内含详细讲解(涵盖入门到精通,自测 Vue 掌握程度)

    前言 本文以前端面试官的角度出发,对 Vue 框架中一些重要的特性.框架的原理以问题的形式进行整理汇总,意在帮助作者及读者自测下 Vue 掌握的程度.本文章节结构以从易到难进行组织,建议读者按章节顺序 ...

  7. 搭建本地yum源出现:mount: 在 /dev/sr0 上找不到媒体

    2021-07-27 在练习环境搭建时,因为是离线环境,故先搭建本地yum源,但是出现了一个往常没有的问题:mount: 在 /dev/sr0 上找不到媒体,参考其他博主的文章得到解决方法. 排查问题 ...

  8. centos7 wget安装Tomcat7

    2021-07-15 1.环境介绍 操作系统:centos7 jdk版本:jdk1.8.0.211 tomcat版本:tomcat7.0.109 2. 检查系统中是否已经安装 jdk ,如未安装, 请 ...

  9. Python中的变量以及变量的命名

    1.变量的定义 在 python 中,每个变量在使用前都必须赋值,变量赋值以后该变量才会被创建 等号(=)用来给变量赋值 =左边是一个变量名 =右边是存储在变量中的值 变量名=值 变量定义之后,后续就 ...

  10. Microsoft Remote Desktop 通过 .rdp 文件登录

    最近在淘宝上买了「市场洞察」子账号,说是子账号,其实是需要登录到他们的 Windows 服务器上才能用的.并且子账号也是 5-6 个人共用的,且不说远程服务器很老又有延迟,经常是我想添加一个监控店铺或 ...