UNION ALL 不能替代 FULL JOIN,二者解决不同问题:前者纵向拼接同结构数据,后者横向关联两表记录;MySQL需用LEFT JOIN加RIGHT JOIN再UNION模拟FULL JOIN。

UNION ALL 和 FULL JOIN 根本不是替代关系
直接说结论:UNION ALL 不能替代 FULL JOIN,它们解决的是完全不同的问题。强行“替换”只会让结果错得离谱——比如把本该横向拼接的关联字段(如用户+订单信息)变成纵向堆叠的碎片行(用户行 + 订单行),丢失所有业务语义。
你真正在意的其实是“MySQL里怎么实现FULL JOIN效果”
MySQL 不支持 FULL JOIN(截至 8.0.32 仍报 ERROR 1064),所以开发者常误以为“用 UNION 就是替代”。实际要模拟 FULL JOIN,必须组合使用:
-
LEFT JOIN获取左表全量 + 右表匹配或 NULL -
RIGHT JOIN(或反向LEFT JOIN)获取右表独有部分 -
UNION(注意:不是UNION ALL)合并,否则交集行会重复两次
典型写法:
SELECT a.id, a.name, b.value FROM table_a a LEFT JOIN table_b b ON a.id = b.id UNION SELECT a.id, a.name, b.value FROM table_b b LEFT JOIN table_a a ON a.id = b.id WHERE a.id IS NULL;
这里必须用 UNION,不是 UNION ALL;字段顺序、类型、NULL 补位(如 NULL AS value)都得手动对齐。
真正该用 UNION ALL 的场景:结构一致、无需关联
当你需要的是“把两批同结构数据简单拼起来”,而不是“按某字段对齐两表记录”,才轮到 UNION ALL 出场。常见于:
- 合并多个时间分区表:
SELECT * FROM logs_202610 UNION ALL SELECT * FROM logs_202611 - 汇总不同来源的相同业务实体:
SELECT id, name FROM internal_users UNION ALL SELECT id, name FROM ldap_users - ETL 中追加历史快照,且确认无重复或不需去重
性能上,UNION ALL 比 UNION 快得多——它跳过排序和去重;但前提是,你真的不需要去重,也不依赖字段间的逻辑关联。
最容易被忽略的坑:NULL 连接键导致 WHERE 失效
在模拟 FULL JOIN 的右独有部分时,别写 WHERE a.id NOT IN (SELECT id FROM table_a)。只要 table_a.id 允许为 NULL,整个条件就静默失效(NOT IN 遇 NULL 返回 UNKNOWN)。必须改用:
WHERE NOT EXISTS (SELECT 1 FROM table_a a2 WHERE a2.id = b.a_id)
或者显式处理 NULL:WHERE a.id IS NULL OR a.id NOT IN (SELECT id FROM table_a WHERE id IS NOT NULL)。这个细节在生产环境查半天才发现,值得提前卡住。

















