Skip to content

sql-inner-joins

SQL JOIN 子句是一个基本工具,用于根据表之间相关的列组合来自两个或多个表的行。这允许您查询逻辑上相关但为范式化目的而单独存储的数据。

INNER JOIN 关键字选择在两个表中具有匹配值的记录。它是最常见的连接类型。如果一个表中的行在另一个表中没有对应的匹配项,则该行将从结果集中排除。

可以将其想象成维恩图 (Venn diagram) 中两个集合的交集。您只会获得重叠部分中存在的数据。

注意:INNER JOIN 是大多数 SQL 数据库中默认的连接类型。单独使用 JOIN 关键字与 INNER JOIN 同义。

强烈推荐使用现代、显式的 INNER JOIN 语法,因为它更清晰明了。

SELECT
t1.column_name,
t2.column_name
FROM table1 AS t1
INNER JOIN table2 AS t2 ON t1.common_column = t2.common_column;

应遵循的关键最佳实践:

  • 使用表别名: 为您的表分配简短、逻辑的别名(例如,Customers AS c,Orders AS o)。这会使您的查询更具可读性,尤其是在连接多个表时。
  • 限定列名: 在列名前加上表别名(例如,c.ID,o.Amount)。这可以防止当表具有相同名称的列时出现歧义,并提高可读性。
  • 分离连接逻辑: ON 子句应仅包含连接表的条件。过滤条件应放在 WHERE 子句中。

示例:连接 Customers 表和 Orders 表

Section titled “示例:连接 Customers 表和 Orders 表”

我们来设置两个表:Customers 和 Orders。Orders 表有一个 CustomerID 列,它是引用 Customers 表中 ID 的外键。

CREATE TABLE Customers (
ID INT PRIMARY KEY,
Name VARCHAR(100) NOT NULL,
Age INT NOT NULL,
City VARCHAR(100)
);
INSERT INTO Customers (ID, Name, Age, City) VALUES
(1, 'Ramesh', 32, 'Ahmedabad'),
(2, 'Khilan', 25, 'Delhi'),
(3, 'Kaushik', 23, 'Kota'),
(4, 'Chaitali', 25, 'Mumbai');
CREATE TABLE Orders (
OrderID INT PRIMARY KEY,
OrderDate DATE NOT NULL,
CustomerID INT,
Amount DECIMAL(10, 2)
);
INSERT INTO Orders (OrderID, OrderDate, CustomerID, Amount) VALUES
(101, '2023-11-20', 2, 1560.00),
(102, '2023-10-08', 3, 3000.00),
(103, '2022-05-20', 4, 2060.00),
(104, '2023-10-08', 3, 1500.00);

现在,我们连接它们以查看哪个客户下了哪个订单。我们只希望看到下过订单的客户。

SELECT
c.ID AS CustomerID,
c.Name AS CustomerName,
o.Amount,
o.OrderDate
FROM Customers AS c
INNER JOIN Orders AS o ON c.ID = o.CustomerID;

请注意,没有订单的 Ramesh(ID 1)未出现在结果中。

客户ID客户名称金额订单日期
2Khilan1560.002023-11-20
3Kaushik3000.002023-10-08
4Chaitali2060.002022-05-20
3Kaushik1500.002023-10-08

您可以链式使用 INNER JOIN 子句来组合三个或更多表。每个 JOIN 子句将一个额外的表连接到目前为止构建的结果集。

我们添加一个 Shippers 表并将其链接到 Orders 表。

CREATE TABLE Shippers (
ShipperID INT PRIMARY KEY,
ShipperName VARCHAR(100)
);
-- 向 Orders 表添加一个 ShipperID 列
ALTER TABLE Orders ADD COLUMN ShipperID INT;
INSERT INTO Shippers (ShipperID, ShipperName) VALUES
(1, 'Speedy Express'),
(2, 'United Package');
-- 更新订单的运输商信息
UPDATE Orders SET ShipperID = 1 WHERE OrderID IN (101, 103);
UPDATE Orders SET ShipperID = 2 WHERE OrderID IN (102, 104);

现在,我们可以连接所有三个表,以获得每个订单的完整视图。

SELECT
o.OrderID,
c.Name AS CustomerName,
o.Amount,
s.ShipperName
FROM Customers AS c
INNER JOIN Orders AS o ON c.ID = o.CustomerID
INNER JOIN Shippers AS s ON o.ShipperID = s.ShipperID;
订单ID客户名称金额运输商名称
101Khilan1560.00Speedy Express
103Chaitali2060.00Speedy Express
102Kaushik3000.00United Package
104Kaushik1500.00United Package

将 INNER JOIN 与 WHERE 子句结合使用

Section titled “将 INNER JOIN 与 WHERE 子句结合使用”

连接表后,您通常需要筛选结果。这通过在所有 JOIN 子句之后添加 WHERE 子句来完成。

让我们查找所有金额大于 2000.00 的订单。

SELECT
c.ID,
c.Name,
o.OrderDate,
o.Amount
FROM Customers AS c
INNER JOIN Orders AS o ON c.ID = o.CustomerID
WHERE o.Amount > 2000.00;

此查询首先连接表以获取所有客户/订单对,然后筛选结果集,只保留符合 WHERE 条件的行。

ID姓名订单日期金额
3Kaushik2023-10-083000.00
4Chaitali2022-05-202060.00
  • 意外的笛卡尔积: 忘记 ON 子句(或提供了不正确的子句)可能导致第一个表中的每一行与第二个表中的每一行连接。这会生成庞大、不正确的结果集并严重影响性能。
  • 在未索引的列上连接: 在未索引的列(特别是主键或外键)上连接表在大型表上可能会非常慢。请始终确保您的连接键已索引。
  • 隐式 JOIN 语法: 避免使用旧的基于逗号的语法(FROM table1, table2 WHERE table1.id = table2.id)。它将连接和过滤逻辑混淆,使查询更难阅读和维护。