SQL JOIN 详解:LEFT 和 INNER 的区别

把韦恩图忘了吧。JOIN 做的事是把两边的行配对,再横着拼成一行。真正区分各种 join 的只有一个问题:左边那行没配上的时候会怎样?INNER 把它丢掉,LEFT 把它留下,右边填 NULL。

🎙️ 发布并录制于: ·

匹配是怎么拼出结果行的

先想行的配对,别想圆圈。对第一张表里的每一行,数据库会去第二张表里找出所有满足连接条件的行。一个客户有两笔订单,结果里就成了两行。inner join 只保留配对成功的那些。

-- users                        -- orders
-- id | name                    -- id | user_id | amount
-- 1  | Ada                     -- 1  | 1       | 19.99
-- 2  | Lin                     -- 2  | 1       | 5.00
-- 3  | Sam                     -- 3  | 2       | 42.50
--          (Sam has no orders — watch what happens to Sam)
SELECT users.name, orders.amount
FROM orders
JOIN users ON orders.user_id = users.id;

-- Ada | 19.99
-- Ada |  5.00      ← Ada matched twice → appears twice
-- Lin | 42.50
-- (no Sam. no match = no row. that's INNER.)

LEFT JOIN 保住写在前面的那张表

left join 承诺保留写在前面那张表的每一行,哪怕它一个搭子都找不到。第二张表缺的那些列,会被填成 null。想决定谁写在前面,把需求念出来:每个用户和他的订单,那 users 就得放前面。

SELECT users.name, orders.amount
FROM users
LEFT JOIN orders ON orders.user_id = users.id;

-- Ada | 19.99
-- Ada |  5.00
-- Lin | 42.50
-- Sam | NULL       ← kept! right side filled with NULL

找出没有匹配的那些行

要找从来没下过单的客户,先用 left join 把所有客户留住,再挑出订单那一侧为空的行。要记住的故障症状是:给订单加了个过滤条件之后,客户少了几个。把那个条件搬进连接条件里,没配上的客户才能活下来。

-- "users who never ordered anything"
SELECT users.name
FROM users
LEFT JOIN orders ON orders.user_id = users.id
WHERE orders.id IS NULL;      -- the missing match IS the filter
-- → Sam
能吃掉你一下午的 bug
在 LEFT JOIN 的 WHERE 里给表加一个普通条件,比如 WHERE orders.amount > 10,你的 NULL 行就没了:NULL > 10 不成立,Sam 被过滤掉,LEFT JOIN 就这么不声不响地变成了 INNER。解法是把右表的条件写进 ON 里,也就是 ON orders.user_id = users.id AND orders.amount > 10,过滤的是匹配项,没配上的行照样留着。

更多表,以及 join 家族剩下的成员

三张表的连接不是什么新东西。先连上一张,再把下一张连到已经变宽的结果上。别名起短一点,连接关系才看得清。right join 只是多塞给你一套思维模型,没有别的好处;把表的顺序调一下,写成 left join。

SELECT u.name, o.amount, p.title
FROM orders o
JOIN users    u ON o.user_id = u.id
JOIN products p ON o.product_id = p.id;
-- each JOIN glues one more table onto the widening row.
-- short aliases (o, u, p) keep it readable.
RIGHT JOIN   -- LEFT JOIN with the tables swapped. almost nobody
             -- writes it; rewrite as LEFT and keep one mental model.
FULL JOIN    -- keep unmatched rows from BOTH sides. rare; audits.
CROSS JOIN   -- every pairing (no ON). sizes × colors = variants.
📚 本页是 SQL 系列中的一篇。完整速成课讲 NULL 的坑、GROUP BY 和 UPDATE 惨案,全部配有音频:10 分钟学会 SQL →

Tell me what missed

A correction is more useful than a compliment. This goes straight to the person who writes SwiftGrasp.

Was this page useful?
0/1000

Please do not include passwords, private keys, or personal information.