ZetCode

MySQL 连接表

最后修改于 2023 年 1 月 10 日

在本 MySQL 教程中,我们将连接 MySQL 中的表。

从关系数据库获得真正力量和好处来自于连接表。 SQL JOIN 子句组合数据库中两个或多个表的记录。 基本上有两种类型的连接:INNEROUTER

在本教程中,我们将使用 CustomersReservations 表。

mysql> SELECT * FROM Customers;
+------------+-------------+
| CustomerId | Name        |
+------------+-------------+
|          1 | Paul Novak  |
|          2 | Terry Neils |
|          3 | Jack Fonda  |
|          4 | Tom Willis  |
+------------+-------------+

这些是 Customers 表中的值。

mysql> SELECT * FROM Reservations;
+----+------------+------------+
| Id | CustomerId | Day        |
+----+------------+------------+
|  1 |          1 | 2009-11-22 |
|  2 |          2 | 2009-11-28 |
|  3 |          2 | 2009-11-29 |
|  4 |          1 | 2009-11-29 |
|  5 |          3 | 2009-12-02 |
+----+------------+------------+

这些是 Reservations 表中的值。

CustomersReservations 都有一个 CustomerId 列。 它是关系列。 如果它在两个表中具有相同的名称,我们可以使用 USING (CustomerId) 语法。 如果名称不同,例如我们有 CustomerIdCId,我们将使用 ON Customers.CustomerId = Reservations.CId 语法。

MySQL 内连接

内连接是最常见的连接类型。 它也是默认的连接。 内连接仅选择数据库表中具有匹配值的那些记录。 我们有三种类型的 INNER JOINSINNER JOINNATURAL INNER JOINCROSS INNER JOININNER 关键字可以省略。

INNER JOIN

mysql> SELECT Name, Day FROM Customers AS C JOIN Reservations 
    -> AS R ON C.CustomerId=R.CustomerId;
+-------------+------------+
| Name        | Day        |
+-------------+------------+
| Paul Novak  | 2009-11-22 |
| Terry Neils | 2009-11-28 |
| Terry Neils | 2009-11-29 |
| Paul Novak  | 2009-11-29 |
| Jack Fonda  | 2009-12-02 |
+-------------+------------+
5 rows in set (0.00 sec)

在此 SELECT 语句中,我们选择了所有已进行预订的客户。 Paul Novak 和 Terry Neils 进行了两次预订。 Jack Fonda 进行了一次。 Tom Willis 缺席,他还没有进行任何预订。 请注意,我们省略了 INNER 关键字。

该语句等效于以下语句

mysql> SELECT Name, Day FROM Customers, Reservations
    -> WHERE Customers.CustomerId=Reservations.CustomerId;
+-------------+------------+
| Name        | Day        |
+-------------+------------+
| Paul Novak  | 2009-11-22 |
| Terry Neils | 2009-11-28 |
| Terry Neils | 2009-11-29 |
| Paul Novak  | 2009-11-29 |
| Jack Fonda  | 2009-12-02 |
+-------------+------------+

我们得到相同的数据。

CROSS INNER JOIN

CROSS INNER JOIN 将一个表中的所有记录与另一个表中的所有记录组合起来。 这种类型的连接几乎没有实际价值。 它也被称为记录的笛卡尔积。

mysql> SELECT Name, Day FROM Customers CROSS JOIN Reservations;
+-------------+------------+
| Name        | Day        |
+-------------+------------+
| Paul Novak  | 2009-11-22 |
| Paul Novak  | 2009-11-28 |
| Paul Novak  | 2009-11-29 |
| Paul Novak  | 2009-11-29 |
| Paul Novak  | 2009-12-02 |
| Terry Neils | 2009-11-22 |
| Terry Neils | 2009-11-28 |
| Terry Neils | 2009-11-29 |
| Terry Neils | 2009-11-29 |
| Terry Neils | 2009-12-02 |
| Jack Fonda  | 2009-11-22 |
...

可以使用以下 SQL 语句实现相同的结果

SELECT Name, Day FROM Customers, Reservations;

MySQL 外连接

一个 外连接 并不要求两个连接表中的每条记录都有匹配的记录。 外连接有三种类型。 左外连接、右外连接和全外连接。 在本教程创建时,MySQL 不支持全外连接。

正如我们上面已经提到的,内连接是最常见的。 外连接可能有助于找出孤立记录。 如果一个人没有进行任何预订,他还是客户吗? 如果我们无法将其与客户匹配,那么预订有效吗?

LEFT OUTER JOIN

LEFT OUTER JOIN 返回左表中的所有值,即使与右表不匹配。 在此类行中,将有 NULL 值。 换句话说,左外连接返回左表中的所有值,加上右表中的匹配值。 请注意,可以省略 OUTER 关键字。

mysql> SELECT Name, Day FROM Customers LEFT JOIN Reservations
    -> ON Customers.CustomerId=Reservations.CustomerId;
+-------------+------------+
| Name        | Day        |
+-------------+------------+
| Paul Novak  | 2009-11-22 |
| Paul Novak  | 2009-11-29 |
| Terry Neils | 2009-11-28 |
| Terry Neils | 2009-11-29 |
| Jack Fonda  | 2009-12-02 |
| Tom Willis  | NULL       |
+-------------+------------+

在这里,我们有所有客户及其预订,以及一个没有预订的客户。 他的行中有一个 NULL 值。

我们可以使用 USING 关键字来实现相同的结果。 这是因为关系列在两个表中具有相同的名称。 SQL 语句将不太冗长。

mysql> SELECT Name, Day FROM Customers LEFT JOIN Reservations
    -> USING (CustomerId);
+-------------+------------+
| Name        | Day        |
+-------------+------------+
| Paul Novak  | 2009-11-22 |
| Paul Novak  | 2009-11-29 |
| Terry Neils | 2009-11-28 |
| Terry Neils | 2009-11-29 |
| Jack Fonda  | 2009-12-02 |
| Tom Willis  | NULL       |
+-------------+------------+

相同的结果,使用更短的 SQL 语句。

RIGHT OUTER JOIN

RIGHT OUTER JOINRIGHT JOIN 是一样的。 它给出了两个表中匹配的所有记录以及右表的所有可能性。 孤立的右记录在左侧显示 NULL

mysql> SELECT Name, Day FROM Customers RIGHT JOIN
    -> Reservations USING (CustomerId);
+-------------+------------+
| Name        | Day        |
+-------------+------------+
| Paul Novak  | 2009-11-22 |
| Terry Neils | 2009-11-28 |
| Terry Neils | 2009-11-29 |
| Paul Novak  | 2009-11-29 |
| Jack Fonda  | 2009-12-02 |
+-------------+------------+

这是两个表右连接的输出。 右侧表 (Reservations) 的所有记录在左侧 (Customers) 都有匹配的记录。

MySQL 自然连接

自然连接链接两个表中具有相同名称的所有列。 在我们的 ustomersReservations 表中,我们有一个名为 CustomerId 的列。

NATURAL INNER JOIN

NATURAL INNER JOIN 自动使用所有匹配的列名进行连接。 在我们的表中,我们在两个表中都有一个名为 CustomerId 的列。

mysql> SELECT Name, Day FROM Customers NATURAL JOIN Reservations;
+-------------+------------+
| Name        | Day        |
+-------------+------------+
| Paul Novak  | 2009-11-22 |
| Terry Neils | 2009-11-28 |
| Terry Neils | 2009-11-29 |
| Paul Novak  | 2009-11-29 |
| Jack Fonda  | 2009-12-02 |
+-------------+------------+

我们得到相同的数据。 SQL 语句不太冗长。

NATURAL LEFT OUTER JOIN

NATURAL LEFT OUTER JOIN 给出了表中所有匹配的记录和左表中的所有其他记录。 它会自动使用所有匹配的列名进行连接。

mysql> SELECT Name, Day FROM Customers 
    -> NATURAL LEFT JOIN Reservations;
+-------------+------------+
| Name        | Day        |
+-------------+------------+
| Paul Novak  | 2009-11-22 |
| Paul Novak  | 2009-11-29 |
| Terry Neils | 2009-11-28 |
| Terry Neils | 2009-11-29 |
| Jack Fonda  | 2009-12-02 |
| Tom Willis  | NULL       |
+-------------+------------+

相同的结果,但使用更少的击键。

NATURAL RIGHT OUTER JOIN

NATURAL RIGHT OUTER JOIN 给出了表中所有匹配的记录和右表中的所有其他记录。 它会自动使用匹配的列名进行连接。

mysql> SELECT Name, Day FROM Customers
    -> NATURAL RIGHT JOIN Reservations;
+-------------+------------+
| Name        | Day        |
+-------------+------------+
| Paul Novak  | 2009-11-22 |
| Terry Neils | 2009-11-28 |
| Terry Neils | 2009-11-29 |
| Paul Novak  | 2009-11-29 |
| Jack Fonda  | 2009-12-02 |
+-------------+------------+

快速回顾

接下来,我们将创建两个小表来回顾我们在这里学到的内容。

mysql> CREATE TABLE AA(A INTEGER);
mysql> CREATE TABLE BB(B INTEGER);
mysql> INSERT INTO AA VALUES(1);
mysql> INSERT INTO AA VALUES(2);
mysql> INSERT INTO AA VALUES(3);
mysql> INSERT INTO AA VALUES(4);
mysql> INSERT INTO BB VALUES(3);
mysql> INSERT INTO BB VALUES(4);
mysql> INSERT INTO BB VALUES(5);
mysql> INSERT INTO BB VALUES(6);

mysql> SELECT * FROM AA;
+------+
| A    |
+------+
|    1 |
|    2 |
|    3 |
|    4 |
+------+

mysql> SELECT * FROM BB;
+------+
| B    |
+------+
|    3 |
|    4 |
|    5 |
|    6 |
+------+

我们已经创建并填充了两个包含数字数据的表。 表 AA 有两个唯一数字 (1, 2),表 BB 也有两个唯一数字 (5, 6)。 它们共享两个数字 (3, 4)。

INNER JOIN

mysql> SELECT * FROM AA JOIN BB ON A = B;
+------+------+
| A    | B    |
+------+------+
|    3 |    3 |
|    4 |    4 |
+------+------+

这是两个表的 INNER JOIN。 我们仅从两个表中获取匹配的值。

LEFT OUTER JOIN

mysql> SELECT * FROM AA LEFT JOIN BB ON A = B;
+------+------+
| A    | B    |
+------+------+
|    1 | NULL |
|    2 | NULL |
|    3 |    3 |
|    4 |    4 |
+------+------+

这是两个表的 LEFT OUTER JOIN。 我们获得匹配值加上左表中没有匹配记录的值。

RIGHT OUTER JOIN

mysql> SELECT * FROM AA RIGHT JOIN BB ON A = B;
+------+------+
| A    | B    |
+------+------+
|    3 |    3 |
|    4 |    4 |
| NULL |    5 |
| NULL |    6 |
+------+------+

这是两个表的 RIGHT OUTER JOIN。 我们获得匹配值加上右表中没有匹配记录的值。

在本 MySQL 教程中,我们正在连接表。