mysql中UNION与UNION ALL的合并查询语法

10次阅读

union 和 UNION ALL 的核心区别在于是否去重:UNION 自动去重(隐式 DISTINCT),UNION ALL 直接拼接;前者性能低需排序去重,后者无额外开销;两者均要求列数相同、类型兼容,列名以首个 select 为准。

mysql中UNION与UNION ALL的合并查询语法

UNION 和 UNION ALL 的核心区别在哪

根本区别在于是否去重:UNION 会自动去除重复行,UNION ALL 完全不处理重复,直接拼接结果集。这意味着 UNION 内部隐式执行了 DISTINCT 操作,而 UNION ALL 只是物理追加。

实际影响很直接:

  • UNION 性能更低,尤其在大数据量时,需排序 + 去重
  • UNION ALL 几乎无额外开销,执行更快
  • 两者都要求各 SELECT 子句列数相同、对应列类型兼容(mysql 会尝试隐式转换
  • 列名以第一个 SELECT 的字段名为准

什么时候必须用 UNION,不能用 UNION ALL

当你明确需要合并后结果唯一时,比如统计多个渠道的用户 ID 且不能重复计数,或拼接不同条件查出的主键集合用于后续 IN 查询 —— 这时若用 UNION ALL,可能引入重复 ID 导致逻辑错误或性能下降(如子查询中重复值被多次匹配)。

典型场景包括:

  • 多表联合去重取 ID 列表
  • 分页前对多个来源数据统一去重再排序
  • NOT IN / LEFT JOIN ... IS NULL 配合做排除逻辑,重复值会影响结果正确性

ORDER BY 和 LIMIT 在 UNION 中怎么写才合法

ORDER BYLIMIT 不能出现在单个子查询里(除最外层),否则报错:Error 1221 (HY000): Incorrect usage of UNION and ORDER BY

正确写法是把整个 UNION 当作一个派生表,或直接在最后加 ORDER BYLIMIT

SELECT id, name FROM t1 UNION ALL SELECT id, name FROM t2 ORDER BY id DESC LIMIT 10;

注意:

  • ORDER BY 中的字段名必须来自第一个 SELECT 的列(或其别名)
  • 如果想对每个子查询单独排序再合并,得用子查询包装:(SELECT ... ORDER BY x LIMIT n) UNION ALL (SELECT ... ORDER BY y LIMIT m)
  • LIMIT 放在末尾是对合并后整体生效;若要限制每个子查询,必须加括号并分别写

常见错误:列类型不一致导致 UNION 失败

MySQL 对 UNION 各子查询对应列的类型有隐式转换规则,但不是万能的。比如 VARCHAR(10)TEXT 合并可能触发警告或截断;intDECIMAL(10,2) 通常可转,但 jsONTEXT 混用会报错:ERROR 1267 (HY000): Illegal mix of collations 或类型不兼容。

稳妥做法:

  • 显式用 CAST()CONVERT() 统一类型,例如:CAST(created_at AS date)
  • 避免混用 NULL 和非空字符串,可用 COALESCE(col, '') 对齐
  • 字符集/排序规则不一致时,用 COLLATE utf8mb4_0900_as_cs 显式指定

真正容易被忽略的是:即使语句能跑通,隐式转换也可能悄悄改变数据表现——比如时间字段被转成字符串后排序失效,或者数字精度丢失。上线前务必用真实数据验证结果一致性。

text=ZqhQzanResources