SQL表连接终于讲明白了:INNER JOIN、LEFT JOIN、RIGHT JOIN 一次学透

4 阅读4分钟

SQL表连接终于讲明白了:INNER JOIN、LEFT JOIN、RIGHT JOIN 一次学透

很多人学 SQL,卡得最久的不是 SELECT、WHERE,而是表连接(JOIN)。这篇就不绕弯,直接把 SQL 表连接讲到能上手。


一、为什么一定要学会表连接?

真实业务里,数据通常不会全塞在一张表里。比如电商系统里,用户信息在 users 表,订单信息在 orders 表。你想查“每个订单是谁下的”“哪些用户没下单”,就必须把多张表关联起来查。

JOIN 的本质:把不同表中有关联的数据,按条件拼接起来。

二、先记住 JOIN 的核心结构

SELECT 列名 FROMA JOIN 表B ON 表A.关联字段 = 表B.关联字段;

比如:

SELECT users.user_name, orders.order_id, orders.amount FROM users INNER JOIN orders ON users.user_id = orders.user_id;

ON 说白了就是:两张表到底凭什么配对。这个条件写错,后面全白搭。

三、INNER JOIN:只要两边都能对上

INNER JOIN 只返回两张表中能够匹配成功的数据。

SELECT users.user_name, orders.order_id, orders.amount FROM users INNER JOIN orders ON users.user_id = orders.user_id;

如果用户表里有小王、小李、小张,订单表里只有小王和小李的订单,那么结果中不会出现小张。

一句人话总结: 能配上的留下,配不上的滚。

四、LEFT JOIN:左边全保留,右边能接上就接

LEFT JOIN 的逻辑是:以左表为主,左表的所有记录都保留,右表匹配不上就补 NULL

SELECT users.user_name, orders.order_id, orders.amount FROM users LEFT JOIN orders ON users.user_id = orders.user_id;

这时即使小张没有下单,也会出现在结果中,只不过订单相关字段是 NULL

查“没有下单的用户”时,这是高频写法:

SELECT users.user_id, users.user_name FROM users LEFT JOIN orders ON users.user_id = orders.user_id WHERE orders.order_id IS NULL;

五、RIGHT JOIN:能不用就少用

RIGHT JOIN 和 LEFT JOIN 一样,只是把“主表”换到了右边。大多数团队更习惯把主表写在左侧,所以开发里通常更推荐统一使用 LEFT JOIN,少用 RIGHT JOIN,省得自己给自己上强度。

六、FULL OUTER JOIN:两边都要,谁落单都留下

FULL OUTER JOIN 会保留左右两边全部记录,匹配得上就拼起来,匹配不上就补 NULL。这个在数据核对、对账时很好用。

不过注意:MySQL 不直接支持 FULL OUTER JOIN,很多时候需要用 UNION 模拟。所以如果你是 MySQL 初学者,先把 INNER JOIN 和 LEFT JOIN 吃透,已经够用了。

七、记 JOIN,不如记这个问题

别死背定义,直接问自己一句:

我到底想保留哪张表的全部数据?

这个问题一问,JOIN 类型通常就出来了:

  • INNER JOIN:只要交集
  • LEFT JOIN:左边全保留
  • RIGHT JOIN:右边全保留
  • FULL OUTER JOIN:两边都保留

八、初学者最容易踩的 4 个坑

1)忘了写 ON 条件

SELECT * FROM users JOIN orders;

这要么直接报错,要么变成笛卡尔积。别查数据,查着查着就把数据库现场炸成烟花。

2)关联字段不唯一,结果重复

一对多、多对多关系本来就会让结果行数膨胀。写 JOIN 前先搞清楚关系:一对一?一对多?多对多?否则你会以为是 SQL 抽风,其实是你没想明白。

3)LEFT JOIN 后又在 WHERE 里把右表卡死

SELECT users.user_name, orders.order_id FROM users LEFT JOIN orders ON users.user_id = orders.user_id WHERE orders.amount > 100;

这会把右表为空的记录过滤掉,效果更像 INNER JOIN。更稳的写法是把过滤条件写到 ON 里:

SELECT users.user_name, orders.order_id FROM users LEFT JOIN orders ON users.user_id = orders.user_id AND orders.amount > 100;

4)字段重名不加表前缀

如果两张表里都有 user_id,那你裸写字段名,数据库十有八九会回你一句:字段不明确。老老实实写全,或者直接上表别名:

SELECT u.user_name, o.order_id, o.amount FROM users u LEFT JOIN orders o ON u.user_id = o.user_id;

九、建议直接收藏的 4 个实战模板

1)查订单和对应用户名

SELECT u.user_name, o.order_id, o.amount FROM users u INNER JOIN orders o ON u.user_id = o.user_id;

2)查所有用户及其订单,没有订单也显示

SELECT u.user_name, o.order_id, o.amount FROM users u LEFT JOIN orders o ON u.user_id = o.user_id;

3)查没有下单的用户

SELECT u.user_id, u.user_name FROM users u LEFT JOIN orders o ON u.user_id = o.user_id WHERE o.order_id IS NULL;

4)统计每个用户的订单数

SELECT u.user_name, COUNT(o.order_id) AS order_count FROM users u LEFT JOIN orders o ON u.user_id = o.user_id GROUP BY u.user_name;

十、最后总结

  1. INNER JOIN: 只要匹配成功的数据
  2. LEFT JOIN: 左表全保留,右表匹配不上就 NULL
  3. 查“没有”: 优先想 LEFT JOIN + IS NULL
  4. LEFT JOIN 右表过滤: 很多时候要写在 ON 里,不要乱塞 WHERE

SQL 表连接不难,它只是经常被讲得很绕。一旦你抓住“保留谁”这个核心,JOIN 基本就顺了。