mysql中JOIN操作连接表的几种方式与区别

8次阅读

INNER JOIN只返回两表联结字段值完全相等的记录,不满足条件的行全被过滤;LEFT JOIN保留左表全部行,右表无匹配则补NULL;RIGHT JOIN极少使用,可转为LEFT JOIN;mysql不支持FULL OUTER JOIN,需用union模拟。

mysql中JOIN操作连接表的几种方式与区别

INNER JOIN 只返回匹配的行,不满足条件的数据全被过滤

这是最常用的连接方式,INNER JOIN(或简写为 JON)只保留左表和右表中联结字段值完全相等的记录。一旦某行在任一表中找不到对应匹配,它就不会出现在结果里。

常见错误是误以为它会补空值或保留主表全部数据——其实不会。比如用 users 表关联 orders 表时,没下过单的用户根本不会出现。

  • 等价写法:JOININNER JOIN 完全相同,MySQL 中无区别
  • 性能上通常最优,因优化器可尽早剪枝
  • 若联结字段有 NULL,这些行一定不会被包含(NULL = NULLFALSE

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.yB 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 NULLCOALESCE() 处理,否则结果可能不符合预期。

text=ZqhQzanResources