INNER JOIN 只返回匹配的行,不满足条件的数据全被过滤
这是最常用的连接方式,
INNER JOIN(或简写为
JON)只保留左表和右表中联结字段值完全相等的记录。一旦某行在任一表中找不到对应匹配,它就不会出现在结果里。
常见错误是误以为它会补空值或保留主表全部数据——其实不会。比如用
users表关联
orders表时,没下过单的用户根本不会出现。 等价写法:
JOIN和
INNER JOIN完全相同,MySQL 中无区别 性能上通常最优,因优化器可尽早剪枝 若联结字段有
NULL,这些行一定不会被包含(
NULL = NULL为
FALSE)
LEFT JOIN 保留左表全部行,右表无匹配则补 NULL
LEFT JOIN的关键在于“左表驱动”:无论右表有没有匹配,左表每一行都至少出现一次。没匹配上的右表字段全为
NULL。
典型场景是查“所有用户及其最新订单”,即使部分用户没订单也要列出来。但要注意:如果在
WHERE子句里对右表字段加非空限制(如
WHERE o.status = 'paid'),就可能把本该保留的左表空匹配行给筛掉——这实际退化成了
INNER JOIN。 正确写法:把右表的过滤条件放到
ON子句里,例如
ON u.id = o.user_id AND o.status = 'paid'错误写法:
LEFT JOIN ... ON u.id = o.user_id WHERE o.status = 'paid'→ 丢失无订单用户 索引建议:左表联结字段最好有索引;右表若常用于
ON后的附加条件,相关字段也应考虑联合索引
RIGHT JOIN 很少用,逻辑上可统一转成 LEFT JOIN
RIGHT JOIN是以右表为基准保留全部行,左表无匹配则补
NULL。但它和
LEFT JOIN本质对称,只是左右调换。几乎所有情况都能通过交换表顺序 + 改用
LEFT JOIN实现,可读性和维护性更好。
MySQL 手册明确建议避免使用
RIGHT JOIN,尤其在多表连接中容易绕晕自己。团队代码规范里基本禁止它。 等价转换:
A RIGHT JOIN B ON A.x = B.y⇔
B LEFT JOIN A ON A.x = B.y执行计划几乎一致,无性能差异 嵌套多个
RIGHT JOIN时,阅读顺序与执行顺序反直觉,极易出错
FULL OUTER JOIN 在 MySQL 中不存在,需用 UNION 模拟
MySQL 原生不支持
FULL OUTER JOIN。它的语义是“左右表所有行都保留,各自无匹配的部分用
NULL填充”。要实现类似效果,必须组合
LEFT JOIN+
RIGHT JOIN+
UNION。
SELECT u.id, u.name, o.order_id FROM users u LEFT JOIN orders o ON u.id = o.user_id UNION ALL SELECT u.id, u.name, o.order_id FROM users u RIGHT JOIN orders o ON u.id = o.user_id WHERE u.id IS NULL;
注意这不是严格等价:上面写法会重复出现双方都有匹配的行(即
INNER JOIN部分)。真正严谨的做法要用
UNION(去重)并拆成三部分:
LEFT JOIN(含右表 NULL)、
RIGHT JOIN(含左表 NULL)、再排除交集。但实际业务中极少需要这么复杂,多数时候用两个
LEFT JOIN分别查再合并更清晰。
真正容易被忽略的是 NULL 处理:所有
JOIN类型中,只要字段来自未匹配侧,值就是
NULL,不是空字符串或 0。做聚合或判断前必须显式用
IS NULL或
COALESCE()处理,否则结果可能不符合预期。
