UNPIVOT 是列转行操作,非集合合并工具;它将一行多列(如 sales_q1/sales_q2)转为多行一列(quarter/amount),不参与 UNION ALL 的并集逻辑,仅对已合并结果做变形。

UNPIVOT 不能嵌套在子查询里直接“转换并集”,它本身是列转行操作,不是集合合并工具;真要实现多结果集横向拼接再转成一列,得先用 UNION ALL 拼数据,再套 UNPIVOT —— 但绝大多数场景下,这是绕远路。
UNPIVOT 的真实作用不是合并多个 SELECT 结果
UNPIVOT 是把「一行多列」变成「多行一列」,比如把 sales_q1、sales_q2、sales_q3 三列压成两列:quarter 和 amount。它不处理多个独立 SELECT 语句的输出合并。
常见误解是以为写成这样就能“把两个查询结果并起来再 UNPIVOT”:
SELECT * FROM ( SELECT 'A' col1, 'B' col2 FROM DUAL UNION ALL SELECT 'X' col1, 'Y' col2 FROM DUAL ) UNPIVOT (val FOR src IN (col1, col2));
这确实能跑通,但注意:UNION ALL 是在子查询里完成的“行合并”,UNPIVOT 只是对合并后的结果做列转行 —— 它没参与“并集逻辑”,只是后续变形。
什么时候该用 UNION ALL + UNPIVOT 组合
只有当你要把「结构相同但来源不同」的数据先堆成宽表(每源占一列),再压平为统一维度时,才需要这个组合。典型场景:
- 对比两个统计口径:比如
actual和forecast各自算出的月度值,想压成type('ACTUAL'/'FORECAST')和value两列 - 把多个指标字段(如
cpu_usage、mem_usage、disk_io)按时间点对齐后,转成指标名+数值的键值对格式
关键约束:
-
UNION ALL前后列数、顺序、类型必须严格一致,否则报错ORA-01789: query block has incorrect number of result columns -
UNPIVOT的IN子句里列出的列,必须全部存在于上层查询结果中,且不能是表达式或别名(除非用子查询提前定义好) - Oracle 11g 及以上才支持
UNPIVOT;10g 及更早需用UNION ALL手动模拟
替代方案:多数情况下 UNION ALL 就够了
如果你只是想把 A 表的 id、B 表的 code、C 表的 ref 全部塞进一列叫 all_keys,根本不需要 UNPIVOT:
SELECT id AS all_keys FROM table_a UNION ALL SELECT code FROM table_b UNION ALL SELECT ref FROM table_c;
这样更直白、性能更好、兼容性更强。UNPIVOT 强制你先把数据铺成宽表形式,反而增加中间步骤和内存开销。
容易踩的坑:
- 用
UNION代替UNION ALL导致意外去重(比如不同表里碰巧有相同值) - 在
UNPIVOT的IN列表里写了不存在的列名,报错ORA-00904: "XXX": invalid identifier - 忘了给子查询加别名,Oracle 报
ORA-00933: SQL command not properly ended(尤其在嵌套较深时)
真正难的不是语法拼接,而是想清楚:你到底要的是“多个结果横向堆叠再压扁”,还是“多个结果纵向追加”。后者用 UNION ALL 直接解决;前者才可能牵扯到 UNPIVOT,但必须确保原始数据已对齐为宽表结构 —— 这一步往往比 UNPIVOT 本身更费劲。


















