SQL LEFT JOIN:返回左表全部行与可选匹配
SQL LEFT JOIN 会返回左表中的每一行,并附加右表中匹配的行。在 SQL 术语里,它属于 SQL outer join:如果没有匹配,右侧列会被填充为 NULL。需要无论关联数据是否存在都保留一侧记录时,就应使用它,例如列出所有客户(包括未下单客户)。LEFT JOIN 与 LEFT OUTER JOIN 语义完全一致,OUTER 只是可选写法。
SQL LEFT JOIN 返回全部行示例
输出:
输出将显示在这里...
输出:
+--------+-------+
| name | total |
+--------+-------+
| 阿尔玛 | 79 |
| 阿尔玛 | 150 |
| 本 | NULL |
| 卡拉 | 45 |
+--------+-------+
4 row(s)
这个示例如何工作
customers有三位客户;orders有三条订单,通过customer_id关联。LEFT JOIN orders o ON o.customer_id = c.id会把每位客户与id匹配的订单配对。阿尔玛有两条订单,因此输出两行。- 本没有任何订单。LEFT JOIN 会保留他的行,并把
o.total填成 NULL,而不是把该行丢弃(INNER JOIN 会丢弃)。 ORDER BY c.id, o.id让输出按客户分组且每组内顺序稳定。本的total列为 NULL,表示“没有匹配项”,而不是“金额为 0”。
ON 与 WHERE:为什么过滤位置很关键
把右表过滤条件放在 WHERE 而不是 ON,是 LEFT JOIN 最常见的错误之一,它会悄悄把外连接变成内连接。
-- 错误:WHERE 会丢掉本,因为他的 o.total 是 NULL
SELECT c.name, o.total
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
WHERE o.total > 50;
-- 正确:ON 在连接匹配阶段过滤,本会保留并以 NULL 填充
SELECT c.name, o.total
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id AND o.total > 50;
ON 条件在连接匹配阶段生效:左表未匹配行仍会以 NULL 形式出现。WHERE 在连接之后执行,会过滤掉右侧列为 NULL 的行,从而删除 LEFT JOIN 本来要保留的记录。
反连接:查找没有匹配项的行
LEFT JOIN 配合对右表列的 IS NULL 判断,是查找“缺失关联记录”的标准写法:
SELECT c.name
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
WHERE o.id IS NULL;
该查询只返回本,也就是没有任何订单的客户。这个模式成立的原因是:只有左表未匹配时,o.id 才会是 NULL。NOT EXISTS 也能得到同样结果;如果输出不需要右表列,它通常更直观。
LEFT JOIN 与 INNER JOIN
| LEFT JOIN | INNER JOIN |
|---|---|
| 返回左表全部行,右表未匹配列填充 NULL | 只返回两侧都匹配的行 |
| 行数 ≥ 左表行数 | 行数 ≤ 较小表行数 |
| 需要保留未匹配行时使用(报表、完整性检查) | 每行都必须有两侧有效数据时使用 |
规则:当你必须保留左表全部行时先用 LEFT JOIN;当未匹配行不相关或无效时改用 INNER JOIN。
SQL LEFT JOIN 常见错误
一对多连接导致行倍增
LEFT JOIN 会为每个匹配对生成一行。如果一个客户有十条订单,这个客户会出现十次。不考虑这一点就聚合,会把统计结果放大。
-- 错误:统计的是订单匹配行数,不是客户数
SELECT COUNT(*) FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id;
-- 正确:统计去重后的客户数
SELECT COUNT(DISTINCT c.id) FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id;
**在连接查询中使用 SELECT ***
连接查询里的 SELECT * 会返回重复列名(例如同时出现 c.id 与 o.id),在应用层映射结果时容易产生歧义。应显式列出需要的列。
性能说明
为右表连接键(orders.customer_id)建立索引,让数据库通过索引探测匹配,而不是扫描整张表。若右表很大且只需要其中一部分记录,可先用子查询预过滤,或把条件放进 ON 子句(而不是 WHERE)来减少连接工作量并保留 LEFT JOIN 语义。
常见问题
LEFT JOIN 和 LEFT OUTER JOIN 有什么区别?
没有区别。LEFT JOIN 与 LEFT OUTER JOIN 是 SQL 标准定义的同义写法。PostgreSQL、MySQL、SQLite、SQL Server、Oracle 都把它们视为完全相同。实际开发中通常省略 OUTER。
为什么加了 WHERE 子句后 LEFT JOIN 返回更少行?
如果 WHERE 条件引用右表列,它会过滤掉那些右侧为 NULL 的扩展行,使 LEFT JOIN 在效果上接近 INNER JOIN。要保留左表未匹配行,应把该条件移到 ON 子句中。
什么时候该用 LEFT JOIN 而不是 INNER JOIN?
当左表记录必须无条件出现在结果中时,用 LEFT JOIN,例如完整性报表、缺失数据排查、可选信息补充。若只有匹配行才有效,应使用 INNER JOIN。