union all 更安全高效,因 union 会触发去重排序且语义不可控;视图中使用需严格对齐列数、顺序、类型,并显式处理 null 和类型转换,跨数据库语法包裹要求不同。

能,但必须显式对齐列结构、类型兼容,且不同数据库对语法包裹要求不同;UNION ALL 是更安全、更常用的选择,除非业务强依赖去重。
视图定义里写 UNION 或 UNION ALL 会报错的常见原因
不是语法不支持,而是结构校验失败。数据库在创建视图时会立即检查每个 SELECT 子句的列数、顺序、类型是否一致,稍有不匹配就拒绝创建。
-
SELECT *在任一子查询中出现 → 必报错:字段顺序/别名不一致时,数据库无法推断统一列结构 - 两个子查询同位置列类型冲突 → 比如
INT和VARCHAR直接UNION,SQL Server 可能隐式转成INT导致字符串变0,MySQL 8.0+ 严格模式下直接报错 - 某张表缺某一列没补全 → 必须用
NULL AS col_name或CAST(NULL AS VARCHAR(50)) AS col_name显式占位 - SQL Server 中漏掉外层括号 → 写成
CREATE VIEW v AS SELECT a FROM t1 UNION SELECT b FROM t2会报Incorrect syntax near 'UNION'
UNION ALL 比 UNION 更值得优先用的三个硬理由
这不是风格偏好,而是执行路径和结果语义的根本差异。
- UNION 实际等价于
UNION ALL + DISTINCT + ORDER BY,必然触发临时表与文件排序(Using temporary; Using filesort),100 万行数据下耗时可能相差 10 倍以上 - UNION 的去重是全局的、不可控的——如果两路数据本就来自不同业务域(如主表+归档表),重复值可能是合法冗余(比如迁移未清理干净的订单),UNION 会悄悄吞掉它
- 视图被嵌套引用时(比如报表 SQL 中
SELECT * FROM v_sales_union),UNION 的去重逻辑无法下推,每次调用都重复执行全套流程,I/O 和 tempdb 压力陡增
跨数据库写法兼容性要点
同一段视图 DDL,在 MySQL、PostgreSQL、SQL Server 上可能一个能跑通,另两个直接报错。
- SQL Server:必须用括号包裹整个
UNION ALL语句,即CREATE VIEW v AS (SELECT a,b FROM t1 UNION ALL SELECT x,y FROM t2) - PostgreSQL:括号可选,但建议加上,否则嵌套多层
UNION ALL时运算符优先级易出歧义 - MySQL:允许不加括号,但若子查询含
ORDER BY,必须配合LIMIT或窗口函数,否则报ORDER BY in subquery is not allowed - Oracle:视图定义外层必须有括号,且子查询中禁用独立
ORDER BY,否则报ORA-00907: missing right parenthesis
列名、类型、NULL 值这些细节最容易被忽略
它们不报错,但会让下游查询行为诡异,尤其当视图被 BI 工具或 ORM 自动映射时。
- 列名永远以第一个
SELECT的别名为准,后面子查询里的AS全部被忽略 —— 所以SELECT id AS user_id FROM users后面必须跟SELECT uid AS user_id FROM members,不能只写uid - 类型不兼容时,宁可全转成字符串:
CAST(col AS VARCHAR(100))比依赖隐式转换更可控 -
UNION把多个NULL当作相同值去重,UNION ALL保留全部 —— 这可能暴露你没意识到的空值分布问题,比如某字段在 A 表全为NULL,B 表部分为NULL,合并后统计口径就偏了
列对齐和类型转换是刚性门槛,而 UNION vs UNION ALL 的选择本质是语义权衡:你到底要不要那一层看不见的全局去重逻辑。多数场景下,它既不必要,又代价高昂。










