MySQL不支持FULL OUTER JOIN,需用LEFT JOIN+RIGHT JOIN+UNION(ALL)组合实现:先取左连全集,再补右表独有行并显式填充NULL,UNION ALL保真高效,配合NOT EXISTS避免NULL陷阱。

MySQL根本不支持 FULL OUTER JOIN 语法,直接写会报 ERROR 1064 ——这不是你SQL写错了,是它压根没这个功能。
为什么 UNION 拼 LEFT + RIGHT 会丢数据
常见写法:SELECT * FROM t1 LEFT JOIN t2 ON ... UNION SELECT * FROM t1 RIGHT JOIN t2 ON ... 看似覆盖了两边,但实际有两处硬伤:
-
UNION自动去重,如果某行在 LEFT 和 RIGHT 结果里都出现(比如匹配成功的记录),会被合并成一条;更危险的是,若原始表本身含重复数据(如两个同名用户),这些重复行会被无声抹掉 -
RIGHT JOIN部分没加过滤,会导致交集行重复出现一次,而UNION又靠去重“补救”,掩盖了逻辑缺陷——一旦字段含NULL或索引不全,结果就不可靠 - 性能上,
UNION要排序 + 去重,大表扫描时延迟明显升高
用 UNION ALL + 显式排除交集才保真
真正可控的做法是拆成两段:先拿左表全量(含右表匹配/不匹配),再单独补右表中“左表完全没对应”的记录。关键在第二段的过滤必须用 NOT EXISTS,而不是 NOT IN:
- 第一段:
SELECT e.id, e.name, d.id AS dept_id, d.name AS dept_name FROM employees e LEFT JOIN departments d ON e.department_id = d.id - 第二段:
SELECT NULL AS id, NULL AS name, d.id AS dept_id, d.name AS dept_name FROM departments d WHERE NOT EXISTS (SELECT 1 FROM employees e WHERE e.department_id = d.id) - 两段用
UNION ALL连接,字段数、顺序、类型(尤其是NULL对应的显式类型)必须严格对齐,否则触发ERROR 1222
字段别名和 NULL 类型对齐最容易被忽略
拼接前必须确保左右查询返回的列数一致、同位置字段语义兼容、且 NULL 字段有明确类型提示:
- 错例:
SELECT id, name FROM t1 LEFT JOIN t2 ...和SELECT id, NULL FROM t2 WHERE ...——第二段NULL默认是DECIMAL类型,与name(VARCHAR)冲突 - 正解:显式写成
SELECT NULL AS name或CAST(NULL AS CHAR),让 MySQL 推导出正确类型 - 所有字段必须用别名统一名字,否则
UNION ALL后列头混乱,下游应用取值易出错
最麻烦的不是写法,而是当连接条件字段本身允许为 NULL 时,NOT EXISTS 子查询里的等值判断会失效——这时得先清洗或改用 COALESCE 处理空值,否则“右表独有”那部分就漏掉了。


















