MySQL不支持FULL OUTER JOIN,需用LEFT JOIN+RIGHT JOIN+UNION ALL组合实现:先取左表全量及匹配右表数据,再补右表独有行(WHERE左表ID IS NULL),必须用UNION ALL避免去重误删,且字段名、类型、顺序须严格对齐。
MySQL 不支持 FULL OUTER JOIN,直接写会报错 ERROR 1064;PostgreSQL、SQL Server、Oracle 可以原生使用,但 NULL 处理和连接键质量直接影响结果可信度。
必须用 LEFT JOIN + RIGHT JOIN + UNION ALL 拼接,且两个子查询都要加 WHERE 过滤条件,否则交集行重复、NULL 键漏匹配。
LEFT JOIN 部分保留左表全部,右表不匹配字段为 NULL
RIGHT JOIN 部分只取“右表有、左表无”的行,必须加 WHERE left_table.id IS NULL
UNION ALL,不是 UNION——后者会去重,但两部分的 NULL 行结构相同,会被误删*,否则字段顺序或别名冲突会导致 UNION 失败示例(合并用户表 users 和订单表 orders):
SELECT u.id, u.name, o.order_id, o.amountFROM users uLEFT JOIN orders o ON u.id = o.user_idUNION ALLSELECT u.id, u.name, o.order_id, o.amountFROM users uRIGHT JOIN orders o ON u.id = o.user_idWHERE u.id IS NULL;
语法没问题,但结果里大量 NULL 容易在后续过滤或聚合中“静默丢数据”。比如加了 WHERE amount > 100,所有右表独有行(amount 是 NULL)全被干掉,实际本意可能是“金额超 100 或该用户根本没下单”。
WHERE 条件里涉及任一表的字段,都要考虑 IS NULL 分支NULL?那 FULL OUTER JOIN 会产生笛卡尔爆炸——两表各 3 条 id IS NULL 记录,会产出 9 行ON 子句里排除:ON u.id = o.user_id AND u.id IS NOT NULL AND o.user_id IS NOT NULL
NULL,但业务字段(如 region_code)常有空值,得提前清洗或用 COALESCE 归一化不是语法对了就行。两个系统原始数据结构不同、主键定义不一致、空值含义不统一,直接连会出脏数据。
NULL
INT 和 VARCHAR 连不上;时间字段一个存 UTC 一个存本地时区,JOIN 条件失效status = NULL 表示待审核,系统 B 的 status = NULL 表示已注销——合并后不能简单填 COALESCE(a.status, b.status)
真正难的从来不是写对那一行 FULL OUTER JOIN,而是搞清两边字段背后的真实业务语义。空值怎么解释,缺失代表什么,要不要补默认值——这些不厘清,SQL 写得再漂亮,结果也是误导。