基于湖库一体架构,统一管理结构化、半结构化与非结构化等多模态数据,一个系统承载事务处理、实时分析与 AI 工作负载。
UNPIVOT 子句
更新时间:2026-10-27 18:07:22
描述
UNPIVOT 子句用于将查询结果中的列转换为行,即列转行,是 PIVOT 的逆操作。它把多个列的值合并到同一个列中,同时新增一列来标识原值来自哪一列。
例如,使用 PIVOT 已经把各部门的工资汇总值展开为多个列,使用 UNPIVOT 可以把这些列重新合并为“部门 + 工资”的行记录。
说明
UNPIVOT 子句仅适用于 Oracle 模式。
权限要求
执行 UNPIVOT 查询时,需要当前用户对参与转换的表或视图拥有 SELECT 权限。有关 OceanBase 数据库权限的详细介绍,参见 Oracle 模式下的权限分类。
语法
unpivot_clause:
UNPIVOT [ { INCLUDE | EXCLUDE } NULLS ]
( { column | ( column [, column... ]) }
pivot_for_clause
unpivot_in_clause
)
pivot_for_clause:
FOR { column | ( column [, column... ]) }
unpivot_in_clause:
IN
( { column | ( column [, column... ]) } [ AS { literal | ( literal [, literal... ]) } ]
[, { column | ( column [, column... ]) } [ AS { literal | ( literal [, literal... ]) } ]]
)
参数解释
| 参数 | 说明 |
|---|---|
INCLUDE NULLS |
可选项,转换后值为 NULL 的行也作为结果行输出。 |
EXCLUDE NULLS |
可选项,转换后值为 NULL 的行不作为结果行输出。 |
column |
转换后接收数据的列,即值列。 |
pivot_for_clause |
指定新增的标识列,用于存放 IN 子句中定义的标签值。 |
unpivot_in_clause |
指定要转换为行的列。AS 后面指定该列在标识列中对应的标签值;不指定 AS 时使用列名作为标签值。 |
UNPIVOT 的输出列由三部分组成:未参与转换的列、pivot_for_clause 指定的标识列、unpivot_in_clause 中指定的值列。
注意
不指定 INCLUDE NULLS 或 EXCLUDE NULLS 时,OceanBase 数据库按 EXCLUDE NULLS 处理,即值为 NULL 的行不会输出。该默认行为与 Oracle 数据库(默认 INCLUDE NULLS)不同,如需保留 NULL 行,请显式指定 INCLUDE NULLS。
使用限制
unpivot_in_clause中的列需要能够转换为同一种数据类型,否则会报错ORA-01790: expression must have same datatype as corresponding expression。AS后面只支持常量表达式,不支持使用列或子查询动态生成标签值。- 暂不支持
UNPIVOT作为 joined table 的别名。 - 暂不支持
UNPIVOT操作的目标表是 natural join 的情况。 UNPIVOT之后可以继续使用WHERE、ORDER BY等子句,此时这些子句作用于转换后的结果集。
示例
先创建示例表 emp 并插入数据。
obclient> CREATE TABLE emp (
empno NUMBER(4),
job VARCHAR2(9),
deptno NUMBER(2),
sal NUMBER(7,2)
);
obclient> INSERT INTO emp VALUES
(7369, 'CLERK', 20, 800),
(7499, 'SALESMAN', 30, 1600),
(7521, 'SALESMAN', 30, 1250),
(7566, 'MANAGER', 20, 2975),
(7654, 'SALESMAN', 30, 1250),
(7698, 'MANAGER', 30, 2850),
(7782, 'MANAGER', 10, 2450),
(7788, 'ANALYST', 20, 3000),
(7839, 'PRESIDENT', 10, 5000),
(7844, 'SALESMAN', 30, 1500),
(7876, 'CLERK', 20, 1100),
(7900, 'CLERK', 30, 950),
(7902, 'ANALYST', 20, 3000),
(7934, 'CLERK', 10, 1300);
示例 1:将多个列转换为行
先使用 PIVOT 把各部门的工资汇总值展开为列,并保存为视图。
obclient> CREATE VIEW emp_pivot AS
SELECT *
FROM (SELECT job, deptno, sal FROM emp)
PIVOT (
SUM(sal)
FOR deptno IN (10 AS dept_10, 20 AS dept_20, 30 AS dept_30, 40 AS dept_40)
);
obclient> SELECT * FROM emp_pivot;
查询结果如下:
+-----------+---------+---------+---------+---------+
| JOB | DEPT_10 | DEPT_20 | DEPT_30 | DEPT_40 |
+-----------+---------+---------+---------+---------+
| CLERK | 1300 | 1900 | 950 | NULL |
| SALESMAN | NULL | NULL | 5600 | NULL |
| MANAGER | 2450 | 2975 | 2850 | NULL |
| ANALYST | NULL | 6000 | NULL | NULL |
| PRESIDENT | 5000 | NULL | NULL | NULL |
+-----------+---------+---------+---------+---------+
5 rows in set
再使用 UNPIVOT 把 DEPT_10、DEPT_20、DEPT_30、DEPT_40 四列转换回行,并用 AS 指定标识列的取值。
obclient> SELECT *
FROM emp_pivot
UNPIVOT (
sal
FOR deptno IN (dept_10 AS 10, dept_20 AS 20, dept_30 AS 30, dept_40 AS 40)
)
ORDER BY deptno, job;
查询结果如下:
+-----------+--------+------+
| JOB | DEPTNO | SAL |
+-----------+--------+------+
| CLERK | 10 | 1300 |
| MANAGER | 10 | 2450 |
| PRESIDENT | 10 | 5000 |
| ANALYST | 20 | 6000 |
| CLERK | 20 | 1900 |
| MANAGER | 20 | 2975 |
| CLERK | 30 | 950 |
| MANAGER | 30 | 2850 |
| SALESMAN | 30 | 5600 |
+-----------+--------+------+
9 rows in set
DEPT_40 列的值全部为 NULL,按默认的 EXCLUDE NULLS 行为,SAL 为 NULL 的行(包括 DEPT_40 列对应的 5 行)不会出现在结果中,因此结果只有 9 行。如果希望保留这些行,在 UNPIVOT 后显式指定 INCLUDE NULLS 即可,此时结果行数由 9 行增加到 20 行。
示例 2:不指定标签值
不指定 AS 时,标识列的取值为原列名。
obclient> SELECT *
FROM (
SELECT 1 AS id, 'Laptop' AS product, 100 AS q1, 150 AS q2 FROM dual
)
UNPIVOT (
amount FOR quarter IN (q1, q2)
);
查询结果如下:
+------+---------+--------+---------+
| ID | PRODUCT | QUARTER | AMOUNT |
+------+---------+--------+---------+
| 1 | Laptop | Q1 | 100 |
| 1 | Laptop | Q2 | 150 |
+------+---------+--------+---------+
2 rows in set