Skip to content

SQL Joins

SQL 中的 JOIN 子句用于根据两个或多个表之间的关联列来组合(联合)这些表的行。这是关系型数据库(relational databases)的基石,它允许你检索和分析逻辑相关但存储在不同表中的数据,以减少冗余并提高数据完整性。

想象你有两个表:Customers(客户表)和 Orders(订单表)。Customers 表存储客户信息,而 Orders 表存储订单详情。Orders 表中的每个订单都通过 CustomerID(客户 ID)与一个客户关联。

Customers 表示例:

CustomerIDCustomerNameCountry
1Alfreds FutterkisteGermany
2Ana TrujilloMexico
3Antonio MorenoMexico

Orders 表示例:

OrderIDCustomerIDOrderDate
1030821996-09-18
1030931996-09-19
1031011996-09-20
1031141996-09-21 — 假设 CustomerID 4 在 Customers 表中存在但未在上方显示

CustomerID 列是这两个表的共同列,作为它们之间的链接。JOIN 就是利用这个链接来组合相关的行。

编写 JOIN 的最常用且推荐的方式是使用明确的 JOIN 语法(如 INNER JOIN, LEFT JOIN 等)以及一个指定连接条件的 ON 子句。

示例:使用客户名称检索订单信息

Section titled “示例:使用客户名称检索订单信息”

要获取订单列表以及下订单的客户姓名,可以使用 INNER JOIN:

SELECT
O.OrderID,
C.CustomerName,
O.OrderDate
FROM Orders O
INNER JOIN Customers C ON O.CustomerID = C.CustomerID;

这个查询将产生类似以下的结果:

OrderIDCustomerNameOrderDate
10308Ana Trujillo1996-09-18
10309Antonio Moreno1996-09-19
10310Alfreds Futterkiste1996-09-20

注意:这里使用了表的别名(O 代表 Orders,C 代表 Customers),以使查询更短、更易读,尤其当列名可能不明确时(例如,如果两个表都有一个名为 ID 的列)。

有几种不同类型的 JOIN 操作,用于处理组合数据的不同场景:

  • INNER JOIN(或简写为 JOIN): 只返回基于连接条件在两个表中都有匹配的行。如果一个客户没有订单,或者一个订单引用了一个不存在的客户,这些行将不会出现在结果中。
  • LEFT JOIN(或 LEFT OUTER JOIN): 返回左表(LEFT JOIN 前面提到的表)中的所有行以及右表中匹配的行。如果在右表中没有匹配项,则右表列将返回 NULL 值。当你需要一个表中的所有记录,以及另一个表中任何相关数据时,这很有用。
  • RIGHT JOIN(或 RIGHT OUTER JOIN): 返回右表(RIGHT JOIN 后面提到的表)中的所有行以及左表中匹配的行。如果在左表中没有匹配项,则左表列将返回 NULL 值。这比 LEFT JOIN 不常用,因为通常可以通过交换表的顺序并使用 LEFT JOIN 来达到相同的结果。
  • FULL JOIN(或 FULL OUTER JOIN): 当左表或右表中存在匹配时,返回所有行。如果在一个表中的行没有匹配项,则另一个表中的列将返回 NULL 值。这显示了两个表中的所有数据,并在可能的情况下进行匹配。
  • CROSS JOIN(或笛卡尔积): 返回两个表中行的所有可能的组合。除非有特定意图,否则很少使用这种连接,因为它可能产生非常大的结果集。它通常写成 SELECT * FROM TableA CROSS JOIN TableB;,或者不太明确(且常因错误)地写成 SELECT * FROM TableA, TableB; 且没有 WHERE 子句。
  • SELF JOIN: 这不是一种不同的 JOIN 关键字类型,而是一种常规 JOIN,其中一个表与自身进行连接。这对于查询层级数据或比较同一表中的行非常有用(例如,查找拥有相同经理的员工)。

示例:使用 LEFT JOIN 查看所有客户及其可能拥有的订单

Section titled “示例:使用 LEFT JOIN 查看所有客户及其可能拥有的订单”
SELECT
C.CustomerName,
O.OrderID,
O.OrderDate
FROM Customers C
LEFT JOIN Orders O ON C.CustomerID = O.CustomerID;

这个查询将列出所有客户。如果客户有订单,将显示其订单详细信息。如果客户没有订单,该客户的 OrderID 和 OrderDate 将为 NULL。

如果两个表中的连接列具有完全相同的名称(例如,CustomerID),你可以在某些数据库系统(例如 PostgreSQL, MySQL)中使用 USING 子句作为 ON 子句的简写:

SELECT O.OrderID, C.CustomerName, O.OrderDate
FROM Orders O
INNER JOIN Customers C USING (CustomerID);

常见陷阱:

  • 缺少连接条件: 忘记 ON 子句或提供不正确的子句可能导致笛卡尔积或错误的结果。
  • 模糊的列名: 如果两个表都有同名列(例如,ID),则必须使用表名或别名来限定它们(例如,Customers.ID, Orders.ID)。
  • 理解 NULL 值: 请注意连接列中的 NULL 值如何影响结果,特别是在 INNER JOIN 与 OUTER JOIN 之间。

实际应用:连接(Joins)是任何涉及多个表数据的关系型数据库任务的基础,例如生成报告(如按地区划分的销售额,其中销售额在一个表中,地区在另一个表中),显示综合信息(如产品详细信息与供应商信息),或进行复杂的数据分析。

学习资源:使用维恩图可视化连接非常有帮助。搜索 ‘SQL Join Venn Diagrams’ 可以找到图形化的解释。