课程 5.3: 左连接 - 包含左表中的所有记录
虽然 INNER JOIN 仅返回两个表中匹配的行,但在许多场景中,您可能希望保留一个表中的所有记录,即使它们在另一个表中没有匹配。这正是 左连接(也称为 左外连接)所做的。
什么是左连接?
LEFT JOIN 返回 "左" 表(查询中首先提到的表)中的 所有 行,以及 "右" 表(在 JOIN 关键字后提到的表)中的匹配行。
如果左表中的特定行在右表中没有匹配,数据库仍然会返回左表中的行,但会在所有来自右表的列中填入 NULL。
可视化:
表 A (客户) 表 B (付款)
+----+----------+ +----+----------+
| id | name | | id | amount |
+----+----------+ +----+----------+
| 1 | Alice | <--------> | 1 | 10.00 | (匹配!)
| 2 | Bob | <--------> | 1 | 15.00 | (匹配!)
| 3 | Charlie | <--------? | NULL | (没有匹配,保留 Charlie!)
+----+----------+ +----+----------+
在这个例子中,Charlie 被包含在结果中,即使他没有付款。他的行的 "amount" 将是 NULL.
左连接语法
LEFT JOIN 的语法与 INNER JOIN 相同,但关键字不同:
SELECT
table1.column1,
table2.column2
FROM
table1
LEFT JOIN
table2 ON table1.common_column = table2.common_column;
LEFT JOIN:确保保留table1(左表)中的所有行。ON:匹配的条件。
注意:
LEFT JOIN和LEFT OUTER JOIN是同一回事。关键字OUTER是可选的。
实际示例(Sakila 数据库)
1. 查找所有客户及其付款
假设我们想要一个所有客户的列表,包括那些从未付款的客户。INNER JOIN 会过滤掉没有付款的客户,但 LEFT JOIN 会保留他们。
SELECT
c.first_name,
c.last_name,
p.amount
FROM
customer AS c
LEFT JOIN
payment AS p ON c.customer_id = p.customer_id
ORDER BY
p.amount ASC;
如果您看到 amount 为 NULL 的行,那些是没有付款记录的客户。
2. 识别 "死" 库存
让我们查找所有电影副本(库存),并检查它们是否曾被租用。
SELECT
i.inventory_id,
f.title,
r.rental_id
FROM
inventory AS i
JOIN
film AS f ON i.film_id = f.film_id
LEFT JOIN
rental AS r ON i.inventory_id = r.inventory_id
WHERE
r.rental_id IS NULL;
通过使用 LEFT JOIN 然后过滤 r.rental_id IS NULL,我们可以找到库存中从未被租出的特定项目。
重要考虑事项
- 表的顺序很重要: 在
LEFT JOIN中,FROM后列出的表是 "左" 表。如果您交换表,结果会完全改变。 - 处理 NULL: 使用
LEFT JOIN时,您的应用程序代码需要准备好处理结果中的NULL值。 - 过滤: 如果您在
WHERE子句中放置一个引用右表的条件,您可能会不小心将LEFT JOIN转换为INNER JOIN(这是一个常见的 SQL 陷阱)。
本课的关键要点
- LEFT JOIN 返回左表中的所有行,无论是否存在匹配。
- 当没有找到匹配时,右表中的列将包含 NULL。
- 这是一个强大的工具,用于 查找缺失数据 或生成全面的列表。
- 与
INNER JOIN不同,查询中 表的顺序 对结果有显著影响。