跳转到主要内容
模块 3 · 第 2 课(共 4)课程中的10/57~10 min
模块课程(2/4)

将所有内容保留在左侧:LEFT JOIN

上一课中的 INNER JOIN 有一个重要的副作用:它 删除不匹配的行。如果员工没有部门 (department_id 是 NULL),它们从结果中消失。

有时这就是你想要的。但通常情况并非如此:在人力资源报告中 有必要看到所有员工,包括那些没有部门的员工, 并知道他们是谁。这就是 LEFT JOIN 的用途(完整的,LEFT OUTER JOIN)。

它是如何运作的

SQL
SELECT columns
FROM   table_a
LEFT JOIN table_b ON table_a.x = table_b.y;

用英语阅读:“保留table_a的所有行;对于每一行尝试 附加 table_b 中的一行;如果没有匹配项,请填写以下列 table_b 与 NULL"。

关键字是**LEFT**:它的意思是“左表”,即写的那个 在 FROM 之后。它的所有行都永远存在。

SQL
-- All employees, including those without a department:
SELECT e.first_name,
       e.last_name,
       d.name AS dipartimento
FROM   employees   AS e
LEFT JOIN departments AS d ON e.department_id = d.id;

在我们的数据集中,此查询返回 10 行(每行一名员工)。安德里亚 Costa 具有 department_id = NULL,与 dipartimento = NULL 一起出现 而不是消失。

查找“不匹配”的行

一个非常有用的结果:通过在列上使用 IS NULL 进行过滤 在右侧表中,您准确地找到了不匹配的行:

SQL
-- Orphan employees: no department assigned
SELECT e.first_name, e.last_name
FROM   employees   AS e
LEFT JOIN departments AS d ON e.department_id = d.id
WHERE  d.id IS NULL;

这个技巧在现实世界中一直在使用:“找到我的订单,没有 客户", "没有评论的产品", "从未登录过的用户 在“.

尝试一下

锻炼#sql.m3.l2.e1
尝试:0加载中...

返回未分配部门的员工的名字 (first_name) 和姓氏 (last_name)。一行或多行,两列。

正在加载编辑器...
显示提示

使用 d.id IS NULL 完成 WHERE — 您需要 LEFT JOIN 未找到匹配部门的行。

3 次尝试后可用的解决方案

复习练习

锻炼#sql.m3.l2.e2
尝试:0加载中...

列出所有部门 (departments.name) 及其旁边的员工人数,还包括没有员工的部门(显示 0)。提示:从部门开始,与员工进行 LEFT JOIN,然后进行 GROUP BY + COUNT。

正在加载编辑器...
显示提示

当没有匹配项时,使用 COUNT(e.id)(而不是 COUNT(*))计算 0:由于 LEFT JOIN 行包含 NULL,因此 COUNT(*) 会计算 1。

3 次尝试后可用的解决方案