SQL 反向变换结果集成一列,你想把一个查询结果合并成一列。例如,你希望返回 DEPTNO
等于 10 的全体员工的 ENAME
、JOB
和 SAL
,并且想把 3 列值合并成 1 列。你希望为每一个员工返回 3 行数据,员工之间以空行分隔开。你希望得到如下所示的结果集。
SQL 反向变换结果集成一列 问题描述
你想把一个查询结果合并成一列。例如,你希望返回 DEPTNO
等于 10 的全体员工的 ENAME
、JOB
和 SAL
,并且想把 3 列值合并成 1 列。你希望为每一个员工返回 3 行数据,员工之间以空行分隔开。你希望得到如下所示的结果集。
SQL 反向变换结果集成一列 解决方案
关键在于使用笛卡儿积为每个员工返回 4
行数据。我们需要把每一列变成一行,并且在两个员工之间多留一个空白行。
DB2、Oracle 和 SQL Server
使用窗口函数 ROW_NUMBER OVER
基于 EMPNO
为每一行数据排名(1 ~ 4 行)。然后,使用 CASE
表达式把 3 列数据变成 1 列。
PostgreSQL 和 MySQL
本实例着重介绍如何使用窗口函数为每一行数据提供一个序号,该序号在之后的结果集变换操作中会被用到。在写作本书时,PostgreSQL 和 MySQL 尚未提供这样的窗口函数。
SQL 反向变换结果集成一列 扩展知识
DB2、Oracle 和 SQL Server
首先使用窗口函数 ROW_NUMBER OVER
为 DEPTNO
等于 10 每一位员工生成一个序号。
此时,上面的序号其实并没有意义。我们按照 EMPNO
分区,因而 DEPTNO
等于 10 的所有行的序号都是 1。如果引入笛卡儿积,序号的作用就显现出来了,如下所示。
现在我们需要暂停一下,仔细推敲两个关键的要点。
- class=”第2级无序列表”>每个员工的
RN
值不再是 1,现在它变成了从 1 到 4 循环出现的序列值,原因在于窗口函数会在FROM
和WHERE
子句之后才被评估执行。因此,按照EMPNO
分区就导致当遇到一个新员工时,RN 值会被重置为 1。 - 内嵌视图
FOUR_ROWS
的存在只是为了返回一个包含 4 行数据的结果集。它的作用仅限于此。我们希望为每一列(ENAME
、JOB
和SAL
)返回一行,然后再加上一个空行。
现在,最困难的工作已经完成了,剩下的就是使用 CASE
表达式把每个员工的 ENAME
、JOB
和 SAL
并入一列(为了保证 CASE
成功执行,我们还需要把 SAL 转换成字符串)。