UNION ALL 可用于视图定义,但须严格对齐字段数量、顺序与类型,条件需下推至各子查询,聚合需用子查询或CTE包裹,且结果无序须外层显式排序。

UNION ALL 能直接用于视图定义,但字段对齐、类型兼容和条件下推必须手动处理,否则视图一查就报错。
创建视图时 UNION ALL 的字段必须严格对齐
视图本质是保存的 SELECT 语句,UNION ALL 对列数、顺序、类型的要求在视图里不会放松。常见错误是两个子查询返回列名或数量不一致,比如:SELECT user_id, COUNT(*) FROM login GROUP BY user_id 和 SELECT region, SUM(sales) FROM order GROUP BY region —— 直接 UNION ALL 会触发 ERROR 1222 或 ORA-01789。
正确做法是显式对齐:
- 用别名统一列名:如都写成
key和metric - 缺失字段补
NULL并显式声明类型:如NULL::TEXT或CAST(NULL AS NUMERIC) - 数值类聚合结果建议统一转为相同精度:如
CAST(COUNT(*) AS DECIMAL(12,2))和ROUND(AVG(price), 2)
WHERE 条件不能只写在外层,必须下沉到每个分支
视图一旦建好,后续查询可能加 WHERE dt >= '2026-04-01',但如果原始 UNION ALL 没把条件塞进每个子查询,数据库就得先扫全表再过滤,IO 爆涨、响应变慢。
例如合并销售和退款数据:
- ❌ 错误(全量扫描):
(SELECT id, amt, dt FROM sales UNION ALL SELECT id, amt, dt FROM refunds) WHERE dt >= '2026-04-01' - ✅ 正确(索引可命中):
SELECT id, amt, dt FROM sales WHERE dt >= '2026-04-01' UNION ALL SELECT id, amt, dt FROM refunds WHERE dt >= '2026-04-01'
注意:每个表的 dt 字段是否建了索引、类型是否一致(DATE vs TIMESTAMP),直接影响执行计划。
视图里用 UNION ALL 后不能再直接 GROUP BY,必须套一层
SQL 语法规定集合操作(UNION / UNION ALL)优先级低于 GROUP BY,所以不能写成:SELECT a FROM t1 UNION ALL SELECT a FROM t2 GROUP BY a —— 这会直接语法报错。
想在视图里做二次聚合,必须用子查询或 CTE 包裹:
- 子查询方式:
SELECT key, SUM(metric) FROM (SELECT 'sales' AS key, amount AS metric FROM sales UNION ALL SELECT 'refund', -amount FROM refunds) AS src GROUP BY key - CTE 更易读:
WITH src AS (SELECT ... UNION ALL SELECT ...) SELECT ... FROM src GROUP BY ...
注意:CTE 在 PostgreSQL/SQL Server 中支持良好,但 MySQL 5.7 不支持,得用子查询。
最常被忽略的一点:视图定义里没写 ORDER BY,不代表结果有序;UNION ALL 本身不保证顺序,如果业务依赖顺序(比如前端分页取前 10 条),必须在外层查询显式加 ORDER BY,且排序字段得在视图输出列中存在。

















