sql-inner-joins
SQL INNER JOIN (内连接)
Section titled “SQL INNER JOIN (内连接)”SQL JOIN 子句是一个基本工具,用于根据表之间相关的列组合来自两个或多个表的行。这允许您查询逻辑上相关但为范式化目的而单独存储的数据。
SQL INNER JOIN (内连接)
Section titled “SQL INNER JOIN (内连接)”INNER JOIN 关键字选择在两个表中具有匹配值的记录。它是最常见的连接类型。如果一个表中的行在另一个表中没有对应的匹配项,则该行将从结果集中排除。
可以将其想象成维恩图 (Venn diagram) 中两个集合的交集。您只会获得重叠部分中存在的数据。
注意:INNER JOIN 是大多数 SQL 数据库中默认的连接类型。单独使用 JOIN 关键字与 INNER JOIN 同义。
语法和最佳实践
Section titled “语法和最佳实践”强烈推荐使用现代、显式的 INNER JOIN 语法,因为它更清晰明了。
SELECT t1.column_name, t2.column_nameFROM table1 AS t1INNER 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.OrderDateFROM Customers AS cINNER JOIN Orders AS o ON c.ID = o.CustomerID;请注意,没有订单的 Ramesh(ID 1)未出现在结果中。
| 客户ID | 客户名称 | 金额 | 订单日期 |
|---|---|---|---|
| 2 | Khilan | 1560.00 | 2023-11-20 |
| 3 | Kaushik | 3000.00 | 2023-10-08 |
| 4 | Chaitali | 2060.00 | 2022-05-20 |
| 3 | Kaushik | 1500.00 | 2023-10-08 |
您可以链式使用 INNER JOIN 子句来组合三个或更多表。每个 JOIN 子句将一个额外的表连接到目前为止构建的结果集。
示例:添加运输商
Section titled “示例:添加运输商”我们添加一个 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.ShipperNameFROM Customers AS cINNER JOIN Orders AS o ON c.ID = o.CustomerIDINNER JOIN Shippers AS s ON o.ShipperID = s.ShipperID;| 订单ID | 客户名称 | 金额 | 运输商名称 |
|---|---|---|---|
| 101 | Khilan | 1560.00 | Speedy Express |
| 103 | Chaitali | 2060.00 | Speedy Express |
| 102 | Kaushik | 3000.00 | United Package |
| 104 | Kaushik | 1500.00 | United Package |
将 INNER JOIN 与 WHERE 子句结合使用
Section titled “将 INNER JOIN 与 WHERE 子句结合使用”连接表后,您通常需要筛选结果。这通过在所有 JOIN 子句之后添加 WHERE 子句来完成。
示例:查找高价值订单
Section titled “示例:查找高价值订单”让我们查找所有金额大于 2000.00 的订单。
SELECT c.ID, c.Name, o.OrderDate, o.AmountFROM Customers AS cINNER JOIN Orders AS o ON c.ID = o.CustomerIDWHERE o.Amount > 2000.00;此查询首先连接表以获取所有客户/订单对,然后筛选结果集,只保留符合 WHERE 条件的行。
| ID | 姓名 | 订单日期 | 金额 |
|---|---|---|---|
| 3 | Kaushik | 2023-10-08 | 3000.00 |
| 4 | Chaitali | 2022-05-20 | 2060.00 |
- 意外的笛卡尔积: 忘记
ON子句(或提供了不正确的子句)可能导致第一个表中的每一行与第二个表中的每一行连接。这会生成庞大、不正确的结果集并严重影响性能。 - 在未索引的列上连接: 在未索引的列(特别是主键或外键)上连接表在大型表上可能会非常慢。请始终确保您的连接键已索引。
- 隐式
JOIN语法: 避免使用旧的基于逗号的语法(FROM table1, table2 WHERE table1.id = table2.id)。它将连接和过滤逻辑混淆,使查询更难阅读和维护。