Skip to content

sql-left-joins

LEFT JOIN(也称为 LEFT OUTER JOIN)是组合来自两个表行的一个强大工具。它返回左表(首次提及的表)中的所有记录,以及右表(第二次提及的表)中匹配的记录。如果左表中的某一行在右表中没有匹配项,则结果中右表的所有列都将包含 NULL 值(表示空或无值)。

可以这样理解:‘给我左表中的所有内容,并带上你在右表中能找到的所有匹配信息。‘

SELECT
table1.column1,
table1.column2,
table2.column1
FROM
table1
LEFT JOIN
table2 ON table1.matching_column = table2.matching_column;
  • table1 是左表。
  • table2 是右表。
  • ON 子句指定用于匹配两个表之间行的条件,通常是主键-外键关系。

让我们创建两个表:Employees(员工)和 Departments(部门)。我们将看看 LEFT JOIN 如何连接它们。

-- 员工表
CREATE TABLE Employees (
id INT PRIMARY KEY,
name VARCHAR(100),
department_id INT
);
INSERT INTO Employees VALUES
(1, 'Alice', 101),
(2, 'Bob', 102),
(3, 'Charlie', 101),
(4, 'David', NULL); -- David 未被分配部门
-- 部门表
CREATE TABLE Departments (
id INT PRIMARY KEY,
name VARCHAR(100)
);
INSERT INTO Departments VALUES
(101, 'Sales'),
(102, 'Engineering'),
(103, 'Marketing'); -- 市场部暂无员工

现在,让我们执行一个 LEFT JOIN 来列出所有员工及其部门名称。

SELECT
e.name AS employee_name,
d.name AS department_name
FROM
Employees AS e
LEFT JOIN
Departments AS d ON e.department_id = d.id;

小贴士:使用表别名(例如 Employees 的 e 和 Departments 的 d)可以使你的查询更短、更易读。

上述查询将产生以下结果:

employee_namedepartment_name
AliceSales
BobEngineering
CharlieSales
DavidNULL

关键观察点:

  • Employees(左表)中的所有四名员工都包含在结果中。
  • Alice、Bob 和 Charlie 在 Departments 表中找到了匹配的 department_id,因此显示了他们的部门名称。
  • David 的 department_id 是 NULL,所以没有匹配项。他的 department_name 列显示为 NULL。
  • ‘Marketing’ 部门不在结果中,因为它没有员工关联,并且它在右表中。

5. 常见用例:查找不匹配的记录

Section titled “5. 常见用例:查找不匹配的记录”

LEFT JOIN 一个非常常见且强大的用途是查找左表中没有在右表中找到匹配项的记录。这通过添加 WHERE 子句来过滤右表中列的 NULL 值来实现。

SELECT
e.name AS employee_name
FROM
Employees AS e
LEFT JOIN
Departments AS d ON e.department_id = d.id
WHERE
d.id IS NULL;

此查询首先连接表,然后 WHERE 子句只保留部门 ID 为 NULL 的行,这只发生在没有匹配部门的员工身上。结果将是:

employee_name
David

关键区别在于它们如何处理不匹配的行:

  • LEFT JOIN:保留左表中的所有行,无论它们在右表中是否有匹配项。
  • INNER JOIN:只保留在 两个 表中都满足连接条件的行。它会过滤掉两侧不匹配的行。

如果我们在第一个示例中使用了 INNER JOIN,David 将会被排除在结果之外,因为他没有匹配的部门。

-- 使用 INNER JOIN,结果中将不包含 David。
SELECT e.name, d.name
FROM Employees AS e
INNER JOIN Departments AS d ON e.department_id = d.id;