MySQL 集合查询(
UNION、
UNION ALL、
INTERSECT、
EXCEPT)对新手不算友好——不是语法难,而是容易在语义理解、列对齐和隐式类型转换上栽跟头。
UNION 和 UNION ALL 的区别到底在哪?
新手常以为
UNION就是“去重合并”,
UNION ALL就是“直接拼接”,但实际影响远不止结果行数:
UNION会触发隐式排序 + 去重,MySQL 内部可能临时创建唯一索引,数据量大时明显变慢;
UNION ALL完全跳过这步,性能通常高 2–5 倍 两者都要求每个
SELECT的列数、顺序、类型兼容性一致;若第一列是
INT,第二条的对应列是
VARCHAR,MySQL 会尝试转成字符串,可能导致
WHERE条件失效或索引无法使用
ORDER BY只能加在最后一条语句后,且只能按最终结果集的列名或位置编号(如
ORDER BY 1),不能写在单个
SELECT后面
SELECT id, name FROM users WHERE status = 1 UNION ALL SELECT user_id AS id, full_name AS name FROM admins WHERE active = 1 ORDER BY id;
MySQL 8.0+ 才支持 INTERSECT 和 EXCEPT
很多教程没说清楚版本限制:MySQL 在 8.0.31 之前根本不支持
INTERSECT和
EXCEPT。新手照着文档写,直接报错
ERROR 1064 (42000)。 如果必须模拟交集,得用
INNER JOIN或子查询:
SELECT * FROM a WHERE id IN (SELECT id FROM b)模拟差集(A - B)常用
LEFT JOIN ... IS NULL,比用
NOT IN更安全(后者遇到
NULL会整个结果为空) 即使升级到 8.0.31+,
INTERSECT默认也去重,不带
ALL关键字,这点和
UNION行为不统一,容易混淆
列名和数据类型对齐是隐形雷区
集合查询的结果列名以第一条
SELECT为准,后续语句的别名会被忽略;更麻烦的是 MySQL 对类型的“宽松”处理: 如果第一条选的是
DECIMAL(10,2),第二条是
FLOAT,最终列类型可能是
DOUBLE,精度丢失肉眼难察觉
TEXT和
VARCHAR(255)混用时,
UNION可能强制转成
TEXT,导致
GROUP BY或
ORDER BY性能骤降 建议显式用
CAST()统一关键字段类型,比如:
CAST(created_at AS DATETIME)
真正卡住新手的,往往不是会不会写
UNION,而是查出来结果“看起来对”,但分页错乱、统计不准、接口响应变慢——问题藏在类型隐式转换和执行计划里,得学会看
EXPLAIN FORMAT=TREE输出里的
union_result节点。
