内连接只返回匹配行,外连接保留某一方全部数据;left join应为主流写法,on与where位置影响null过滤;mysql不支持full outer join,可用union all模拟。

内连接只返回匹配行,外连接会保留某一方的全部数据
内连接(INNER JOIN)本质是“交集”:只有左表和右表都存在满足 ON 条件的记录,才会出现在结果里。外连接(LEFT JOIN / RIGHT JOIN)则是“保留+补空”:比如 LEFT JOIN 保证左表所有行都出现,右表没匹配上的字段填 NULL。
- 常见错误现象:
SELECT * FROM users INNER JOIN orders ON users.id = orders.user_id查不到没下过单的用户——这不是 bug,是设计如此 - 使用场景:要查“有订单的用户详情”用内连接;要查“所有用户及其订单(含无订单者)”必须用左外连接
- 性能影响:内连接通常更快,因为优化器能更早剪枝;外连接需构造临时结果并填充
NULL,数据量大时内存和排序开销明显上升
LEFT JOIN 和 RIGHT JOIN 本质可互换,但别写 RIGHT JOIN
RIGHT JOIN 在逻辑上等价于把两张表位置调换后的 LEFT JOIN,但阅读时需要反向理解,容易出错。MySQL 官方文档和主流代码规范都建议统一用 LEFT JOIN,靠调整表顺序来表达意图。
- 错误写法:
SELECT u.name, o.amount FROM users u RIGHT JOIN orders o ON u.id = o.user_id—— 看到RIGHT就得倒着读,费脑还易漏条件 - 正确做法:把主表放左边,关联表放右边,一律用
LEFT JOIN,例如SELECT u.name, o.amount FROM orders o LEFT JOIN users u ON u.id = o.user_id - 兼容性注意:某些 ORM 或 BI 工具对
RIGHT JOIN解析不一致,可能报错或生成低效执行计划
ON 和 WHERE 的位置差异,直接决定 NULL 是否被过滤掉
这是最常踩的坑:ON 是连接时的匹配规则,WHERE 是连接完成后的结果过滤。在外连接中,把本该写在 ON 的条件误写进 WHERE,会导致 LEFT JOIN 变成事实上的内连接。
- 错误示例:
SELECT u.name, o.status FROM users u LEFT JOIN orders o ON u.id = o.user_id WHERE o.status = 'paid'——WHERE会把所有o.status为NULL的行(即无订单用户)全干掉 - 正确写法:若想查“所有用户 + 其已支付的订单”,应把条件移到
ON:SELECT u.name, o.status FROM users u LEFT JOIN orders o ON u.id = o.user_id AND o.status = 'paid' - 原理:优化器先按
ON构建临时结果(含NULL),再用WHERE扫一遍——此时NULL = 'paid'永远不成立,整行就被踢了
MySQL 不支持 FULL OUTER JOIN,但 UNION 能凑合用
当真需要“两边都不丢数据”的全外连接效果时,MySQL 原生不提供 FULL OUTER JOIN 语法,但可用 UNION ALL 拼接两个外连接结果实现等效逻辑。
- 典型场景:合并两套独立系统中的用户表,要列出所有用户 ID,不管在哪边存在
- 实操写法:
(SELECT id, 'A' AS src FROM table_a) UNION ALL (SELECT id, 'B' AS src FROM table_b WHERE id NOT IN (SELECT id FROM table_a))—— 注意用NOT IN排除重复,避免笛卡尔积爆炸 - 风险提示:
UNION ALL不去重,若两边有同 ID 数据需额外处理;大数据量下性能比原生FULL JOIN差不少,建议提前加索引
实际写 SQL 时,先问自己一句:我要的数据,是不是允许某一边为空?如果答案是“是”,那就不能用 INNER JOIN,也别碰 RIGHT JOIN,更得盯紧 ON 和 WHERE 的位置——这三个点卡住,90% 的连接问题就解决了。










