MySQL 零基础教程

MySQL LEFT JOIN

LEFT JOIN(左连接)操作用于从“左”表(在 FROM 子句中提到的第一个表)中检索所有记录,以及从“右”表(在 LEFT JOIN 之后提到的表)中检索匹配的记录。如果在右表中没有找到匹配项,则结果集中来自右表的列将包含 NULL 值。

当你想确保来自某个特定表(左表)的所有数据都出现在结果集中,即使在另一个相关表(右表)中没有对应的数据时,这种类型的连接至关重要。

1. 理解 LEFT JOIN

LEFT JOIN 的主要目的是保留位于 LEFT JOIN 关键字左侧的表中的所有记录。它基于两个表之间的相关列来组合行。如果左表中的某一行在右表中没有匹配的行,LEFT JOIN 仍然会在结果中包含左表的那一行,但会将通常来自右表的所有列填充为 NULL

考虑两个表:Customers(客户)和 Orders(订单)。一个客户可以下多个订单,或者一个客户可能还没有下任何订单。如果你想查看所有客户的列表以及他们可能下过的任何订单,LEFT JOIN 就是合适的选择。而 INNER JOIN(如上一节所述)只会显示已经下过订单的客户,排除那些没有下过单的客户。

LEFT JOIN 的基本语法如下:

SELECT
    column1,
    column2,
    ...
FROM
    TableA AS A
LEFT JOIN
    TableB AS B ON A.common_column = B.common_column;

在这里,TableA 是“左”表,TableB 是“右”表。来自 TableA所有行都将包含在结果中。

1.1 概念示例:部门与员工

想象一个包含两个表的公司数据库:Departments(部门)和 Employees(员工)。每个员工在一个特定的部门工作,但即使目前没有分配任何员工,一个部门也可能存在。

如果你想列出所有部门,并且对于每个部门,列出在其中工作的任何员工,你将使用 LEFT JOINDepartments 表将是你的“左”表。

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

这个查询将返回 Departments 表中的每一个 department_name。如果一个部门有员工,他们的 employee_name 将出现在部门名称旁边。如果一个部门没有员工,它的 department_name 仍然会出现,但该行对应的 employee_name 列将显示为 NULL

2. LEFT JOIN 的实际示例

我们将使用 world 数据库表来进行演示。具体来说,让我们考虑 City(城市)和 Country(国家)表。每个城市都属于一个国家,但并非 Country 表中的每个国家在 City 表中都有城市记录(例如,如果我们只存储了主要城市)。

2.1 示例 1:列出所有国家及其首都

假设我们想要列出每个国家及其首都城市。并非 Country 表中的每个国家都在 City 表中具有其首都的对应条目(可能缺失或未指定)。LEFT JOIN 确保所有国家都被列出。

Country 表有一个 Capital 列,用于存储作为首都的城市的 ID

SELECT
    c.Name AS CountryName,
    cy.Name AS CapitalCity
FROM
    Country AS c
LEFT JOIN
    City AS cy ON c.Capital = cy.ID;

在这个查询中:

  • Country 是左表(别名 c)。所有国家都将被包含。
  • City 是右表(别名 cy)。
  • 连接条件 c.Capital = cy.ID 通过将 Country 表的首都 ID 与 City 表的城市 ID 匹配,将国家与其首都连接起来。
  • 如果一个国家的 Capital 列在 City 表中没有匹配的 ID,该国家的 cy.Name 将显示为 NULL,但国家本身仍然会被列出。

2.2 示例 2:查找在 City 表中没有城市的国家

LEFT JOIN 的一个常见用例是查找左表中在右表中没有匹配项的记录。这是通过将 LEFT JOIN 与检查右表某列中 NULL 值的 WHERE 子句结合使用来实现的。

假设我们想找出所有在我们的 City 表中没有记录任何城市的国家。

SELECT
    co.Name AS CountryName
FROM
    Country AS co
LEFT JOIN
    City AS ci ON co.Code = ci.CountryCode
WHERE
    ci.ID IS NULL;

在这个查询中:

  • Country 是左表 (co)。
  • City 是右表 (ci)。
  • 连接条件尝试将每个国家与其城市链接起来。
  • WHERE ci.ID IS NULL 子句过滤结果,仅包含那些在 City 表中找不到给定国家匹配项的行。这意味着来自 CityID 列将是 NULL,表明该国家没有记录城市。

2.3 示例 3:列出产品及其类别(包括未分类产品)

考虑一个电子商务场景。你有 Products(产品)表和 Categories(类别)表。某些产品可能尚未分配类别。

要列出所有产品及其关联类别,包括尚未分配类别的产品:

SELECT
    p.product_name,
    c.category_name
FROM
    Products AS p
LEFT JOIN
    Categories AS c ON p.category_id = c.category_id;

此查询将返回每个 product_name。如果 product_id 匹配,则显示 category_name。如果某产品的分类 ID 为空或在类别表中找不到匹配项,该产品的 category_name 将为 NULL

4. 总结

LEFT JOIN 是一个强大的工具,用于组合来自多个表的数据,同时保证左表中的所有记录都包含在结果集中。它在创建综合报表(需要查看所有主要实体以及任何相关的次要数据)或识别缺乏关联表对应条目的孤立记录时特别有用。

掌握 LEFT JOIN 能够实现更灵活、更完整的数据检索,防止在无法保证存在匹配项时使用 INNER JOIN 可能导致的数据丢失。在下一课中,我们将探讨 RIGHT JOIN,它的功能与 LEFT JOIN 对称,确保包含来自右表的所有记录。