UNION 去重并可能隐式排序,UNION ALL 保留重复且不排序、性能更优;二者均要求列数相同、类型兼容,列名取自首个 SELECT,ORDER BY 须置于整个语句末尾。

UNION 和 UNION ALL 都用于合并两个或多个 SELECT 查询的结果集,但关键区别在于是否去重和性能表现。
UNION:自动去重 + 默认排序
UNION 会合并结果,并自动去除重复行,同时默认按第一个列升序排序(部分数据库如 MySQL 8.0+ 可能不强制排序,但标准 SQL 行为是“无序”,实际执行中常隐式排序;为安全起见,应显式加 ORDER BY)。使用前需确保各查询的列数、数据类型兼容(可隐式转换),列名以第一个 SELECT 为准。
- 所有 SELECT 的列数必须相同
- 对应位置的列应具有兼容的数据类型(如 VARCHAR 与 CHAR、INT 与 TINYINT 通常可接受)
- 结果列名取自第一个 SELECT 的别名或原始列名
- 若需排序,必须把 ORDER BY 放在整个 UNION 语句末尾(不能放在单个子查询后)
示例:
SELECT name, age FROM studentsUNION
SELECT name, age FROM teachers
ORDER BY age DESC;
UNION ALL:保留全部行 + 不排序
UNION ALL 直接拼接所有结果,不做去重也不排序,因此速度更快、资源消耗更小。适合明确知道无重复,或允许重复的场景(如日志汇总、分表查询)。
- 同样要求列数一致、类型兼容
- 不检查重复,也不调整顺序,结果顺序取决于各子查询执行顺序和内部排序(若子查询含 ORDER BY 且未配合 LIMIT/TOP,多数数据库会忽略该 ORDER BY)
- 如需整体有序,仍须在最后加 ORDER BY
示例:
SELECT 'student' AS role, name, created_at FROM studentsUNION ALL
SELECT 'teacher' AS role, name, hired_at AS created_at FROM teachers
ORDER BY created_at DESC;
常见错误与注意事项
容易出错的地方往往不在语法,而在逻辑一致性:
- 列名/别名不统一:第二个 SELECT 的列别名不会生效,列标题始终来自第一个 SELECT;若想控制显示名,应在第一个 SELECT 中定义别名
- 数据类型冲突:如第一个 SELECT 返回 INT,第二个返回 VARCHAR,可能报错或触发隐式转换失败(尤其在 SQL Server 或 PostgreSQL 中较严格)
- ORDER BY 位置错误:只能出现在整个 UNION 语句末尾;若在某个子查询后写 ORDER BY,多数数据库会报错(除非搭配 TOP/LIMIT)
- NULL 值参与比较:UNION 去重时,NULL 被视为相等,即多行 NULL 会被合并为一行
什么时候选 UNION,什么时候选 UNION ALL?
核心看业务需求是否允许重复:
- 需要唯一结果(如合并用户列表并去重)→ 用 UNION
- 追求性能、确认无重复、或本就希望保留重复(如统计每日订单,不分表去重)→ 用 UNION ALL
- 临时调试或中间结果查看 → 优先 UNION ALL,避免意外排序干扰观察
- 结果要分页(如 LIMIT/OFFSET)→ 先用 UNION ALL 合并再分页更高效;若用 UNION,去重+排序+分页三步开销更大










