mysql等旧版数据库不支持full join,需用left join + right join(或not exists)加union all模拟,注意字段对齐、null补位、避免交集重复及性能开销。

SQL里没有FULL JOIN但可以用UNION ALL模拟
标准SQL中FULL JOIN是存在的,但MySQL直到8.0.29才支持,而更早版本和部分旧部署(如MySQL 5.7)直接报错ERROR 1064。如果你遇到Unknown type of JOIN或查询结果为空却预期有两边数据,大概率是数据库不支持原生FULL JOIN,得手动拼。
- 先用
LEFT JOIN查左表全量 + 右表匹配行 - 再用
RIGHT JOIN(或LEFT JOIN调换表序)查右表有但左表无匹配的行 - 用
UNION ALL合并——注意必须用ALL,否则去重会误删本该保留的重复逻辑行 - 所有SELECT字段顺序、数量、类型要严格一致,否则
UNION报错Column count doesn't match
LEFT JOIN + RIGHT JOIN组合时NULL值怎么对齐
手动模拟FULL JOIN最常踩的坑是字段对不齐:比如左表有user_id、右表叫id,或者一边用COALESCE(name, '')另一边没处理,导致UNION后列语义混乱。
- 显式写出所有字段名,不要用
*,尤其涉及同名列时(如两表都有id) - 用
COALESCE(t1.id, t2.id) AS id统一主键字段,避免一边NULL一边有值造成后续判断困难 - 对非关联字段补
NULL占位,例如t1.name在右表无匹配时需写成NULL AS name,而不是漏掉 - 如果某字段在右表是
NOT NULL但左表允许NULL,合并后该列类型会被推断为可空,应用层要注意判空
性能比原生FULL JOIN差多少
手写UNION ALL方案实际执行两次JOIN再合并,IO和内存开销翻倍,特别是大表+无索引关联字段时,可能从秒级变分钟级。
- 确保关联字段(如
t1.user_id = t2.id)在两张表上都有索引,否则RIGHT JOIN部分会全表扫描 - 加
WHERE条件尽量下推到每个子查询里,别只写在外层,否则先合并再过滤,浪费资源 - PostgreSQL/SQL Server等原生支持
FULL JOIN的引擎,优先用原生语法,执行计划更优 - 如果只是临时查数且数据量
PostgreSQL里FULL JOIN结果NULL太多怎么过滤干净
FULL JOIN天然产出大量NULL,但业务往往只关心“至少一边有数据”的行,不是真要全部笛卡尔补空。
- 外层套
WHERE t1.id IS NOT NULL OR t2.id IS NOT NULL,排除两表都NULL的意外行(理论上不会出现,但某些ON条件写错时会有) - 如果只想看“左有右无”或“右有左无”,直接用
WHERE t1.id IS NULL或WHERE t2.id IS NULL,比在应用层筛更高效 - 注意
ON条件里别写AND t2.status != 'deleted'这类过滤——它会让右表“被过滤掉的行”变成NULL,看起来像“右无匹配”,实则是条件误放,应移到WHERE或右表子查询里
SELECT version()确认数据库能力,再决定走原生还是模拟。很多人卡在第一步就查文档没查对版本号,结果按教程写了FULL JOIN却报错。










