SQL INNER JOIN:合并相互匹配的行
第 5.2 课 · 阅读时间:约 6 分钟 · 练习题 ↓
SQL INNER JOIN 把两张表的行组合起来,只返回连接条件为真的行对,也就是在两张表中都有匹配的行。在本课中,你将学习 INNER JOIN 的语法、表别名的作用、如何连接三张表,以及没有匹配的行会怎样。
在上一课中,你了解了为什么数据会分散在多张表中,以及键如何把它们联系起来。INNER JOIN 是把数据重新组合起来最常用的方式:城市和它所属的国家、付款和对应的客户、演员和他参演的电影。
INNER JOIN 返回什么
INNER JOIN 对两张表的行对检查连接条件,只保留条件为真的行对。
- 第一张表中在第二张表里没有匹配行的行,不会出现在结果中。
- 第二张表中没有匹配的行同样不会出现。
- 有多个匹配的行会出现多次,每个匹配一次。
因此,INNER JOIN 常被描述为两张表的交集。
基本语法
SELECT table1.column1, table2.column2
FROM table1
INNER JOIN table2 ON table1.key_column = table2.key_column;
INNER JOIN指定第二张表。ON设置连接条件,通常是“外键 = 主键”。- 关键字
INNER是可选的:单独写JOIN就表示INNER JOIN。
连接两张表
city 表中存有 country_id,它引用 country 表。要在每个城市旁边显示国家名称:
SELECT city.city, country.country
FROM city
INNER JOIN country ON city.country_id = country.country_id
ORDER BY country.country, city.city;
结果:600 个城市,每个城市都带有所属国家的名称。
当两张表中有同名的列(例如这里的 country_id)时,必须在列名前加上表名,否则数据库会报告列名有歧义。
表别名
较长的表名会让连接查询难以阅读。表别名是在表名后定义的简短名称:
SELECT ci.city, co.country
FROM city AS ci
INNER JOIN country AS co ON ci.country_id = co.country_id
ORDER BY co.country, ci.city;
结果相同。一旦为表指定了别名,就在整个查询中使用该别名。请选择简短但有意义的别名:ci 和 co 比 a 和 b 更容易理解。
连接三张表
一位演员可以出演许多电影,一部电影也有许多演员。这种多对多关系存储在关联表中:film_actor 保存 (actor_id, film_id) 对。要列出演员及其电影片名,需要连接这三张表:
SELECT a.first_name, a.last_name, f.title
FROM actor AS a
INNER JOIN film_actor AS fa ON fa.actor_id = a.actor_id
INNER JOIN film AS f ON f.film_id = fa.film_id
ORDER BY a.last_name, a.first_name, f.title
LIMIT 10;
结果:按演员字母顺序排列的前 10 个“演员-电影”对。
- 第一个连接为每位演员附加其在
film_actor中的行。 - 第二个连接为这些行附加对应的电影。
- 每个
JOIN都基于前一个连接的结果工作,因此可以按需连接任意多张表。
JOIN 与 WHERE 和 ORDER BY 组合
连接之后可以继续使用熟悉的子句。例如,查询 Nick Wahlberg 出演的电影:
SELECT f.title, f.release_year, f.rating
FROM actor AS a
INNER JOIN film_actor AS fa ON fa.actor_id = a.actor_id
INNER JOIN film AS f ON f.film_id = fa.film_id
WHERE a.first_name = 'NICK'
AND a.last_name = 'WAHLBERG'
ORDER BY f.title;
结果:这位演员出演的所有电影的片名、上映年份和分级。
没有匹配的行会消失
INNER JOIN 会悄悄丢弃没有匹配的行。Sakila 中有 1000 部电影,但只有 958 部在 inventory 表中有拷贝:
SELECT f.title, i.inventory_id, i.store_id
FROM film AS f
INNER JOIN inventory AS i ON i.film_id = f.film_id
ORDER BY f.title
LIMIT 10;
结果:电影及其拷贝;42 部没有拷贝的电影根本不会出现,而有多个拷贝的电影会出现多次。
如果没有匹配的行也必须保留在结果中,请使用 LEFT JOIN,你将在下一课中学习它。
要点:
INNER JOIN只返回满足ON条件的行对。- 在另一张表中没有匹配的行会被丢弃;有多个匹配的行会重复出现。
JOIN和INNER JOIN是一样的。- 使用表别名,并为两张表中都存在的列加上表前缀。
- 串联多个
JOIN来经过film_actor这样的关联表。
常见问题
JOIN 和 INNER JOIN 有什么区别?
没有区别。在所有主流数据库中,不指定类型的 JOIN 就是 INNER JOIN。当查询中混用不同类型的连接时,显式写出 INNER JOIN 能让意图更清晰。
为什么我的 INNER JOIN 返回重复的行?
因为某一行在另一张表中有多个匹配。一部在 inventory 中有四个拷贝的电影,在连接 film 和 inventory 后会出现四次。这是连接的正常行为;如果每部电影只需要一行,请进行聚合或过滤。
SQL 中可以连接两张以上的表吗?
可以。每张表添加一个 JOIN ... ON ...。每个连接都把一张新表连接到已经连接好的表上。