似乎您想要一个半连接,例如只需要来自 2 个连接表之一的数据的连接。在这种情况下,所有具有所需条件film
的匹配行的行( )。film_rating_report
rating = 'GE'
这并不完全等同于通常的连接,因为即使第二个表中有 2 行(或更多)行(电影的 2 个评级,都带有'GE'
),我们仍然希望电影放映一次,而不是两次(或更多次),因为它会显示一个通常的连接。
编写半连接有多种方法,最流行的是:
使用EXISTS
相关子查询(@Justin 的回答):
SELECT t1.*
FROM film t1
WHERE EXISTS (SELECT filmid
FROM film_rating_report t2
WHERE t2.rating = 'GE'
AND t2.filmid = t1.id);
使用IN
(不相关的)子查询(@SG 86 的答案):(
这应该非常小心地使用,因为它可能会返回意外的结果 - 或者根本没有 - 如果连接列(filmid
在这种情况下是两个)是 Nullable)
SELECT *
FROM film
WHERE id IN
( SELECT filmid
FROM film_rating_report
WHERE rating = 'GE'
);
使用通常JOIN
的 aGROUP BY
来避免结果中的重复行(@Tomas 的答案):(
请注意GROUP BY
,如果您想在其他版本中编写类似的查询,这种特定用法仅适用于 MySQL 和最新版本的 Postgres DBMS,您必须包括所有列GROUP BY f.filmid, f.title, f.director, ...
:)
SELECT f.*
FROM film AS f
JOIN film_rating_report AS frr
ON f.filmid = frr.filmid
WHERE frr.rating = 'GE'
GROUP BY f.filmid ;
@Tomas'es 答案的变体,在GROUP BY
派生表上完成,然后JOIN
:
SELECT f.*
FROM film AS f
JOIN
( SELECT filmid
FROM film_rating_report
WHERE rating = 'GE'
GROUP BY filmid
) AS frr
ON f.filmid = frr.filmid ;
使用哪一个,取决于 RDBMS 和您使用的特定版本(例如,IN
在大多数 MySQL 版本中应避免使用子查询,因为它们可能会产生低效的执行计划)、您的特定表大小、分布、索引等。
我通常更喜欢该EXISTS
解决方案,但首先使用您拥有或期望在未来拥有的表大小测试各种查询并尝试为您的案例找到最佳的查询索引组合。
加法:如果对组合有一个独特的限制film_rating_report (filmid, rating)
,这意味着没有一部电影会获得两个相同的评级,或者如果有一个更严格(但更合理)的独特限制film_rating_report (filmid)
意味着每部电影最多有一个评级,您可以简化JOIN
解决方案(并摆脱所有其他查询):
SELECT f.*
FROM film AS f
JOIN film_rating_report AS frr
ON f.filmid = frr.filmid
WHERE frr.rating = 'GE' ;