16

我的数据库中目前有 2 个 mysql 表

FilmFilm_Ratings_Report

Film 的主键filmid是用来标识Film_Ratings_Report表中的电影等级的。

我想知道是否可以使用 MYSQL 查询仅搜索收视率表并收集符合特定条件的所有电影 ID,然后使用选定的 ID 从电影表中获取电影标题。下面是我使用的 MYSQL 查询,它不起作用:

SELECT * 
FROM film 
UNION SELECT filmid 
      FROM film_rating_report 
      WHERE rating = 'GE' 
      LIMIT 0,0

我对 MYSQL 比较陌生,并希望对此有任何帮助。

提前致谢

4

5 回答 5

16
SELECT * FROM film WHERE id IN 
  (SELECT filmid FROM film_rating_report WHERE rating = 'GE');

应该管用

于 2013-07-01T08:12:29.183 回答
16

似乎您想要一个半连接,例如只需要来自 2 个连接表之一的数据的连接。在这种情况下,所有具有所需条件film的匹配行的行( )。film_rating_reportrating = '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' ;
于 2013-07-01T10:32:07.610 回答
3

首选的解决方案是使用join,并且不要忘记group by这样您就没有重复的行:

select film.*
from film
join film_rating_report on film.filmid = film_rating_report.filmid
        and rating = 'GE'
group by film.filmid

编辑:正如@ypercube 正确指出的那样,我错误地声称 join 和 group by 的性能优于使用带有existsorin的子查询 - 恰恰相反。

于 2013-07-01T08:17:02.373 回答
1

询问:

SELECT t1.* 
FROM film t1 
WHERE EXISTS (SELECT filmid 
              FROM film_rating_report t2
              WHERE t2.rating = 'GE'
              AND t2.filmid = t1.id);
于 2013-07-01T08:17:42.523 回答
-1

我相信这会起作用,在不知道您的数据库结构的情况下思考(考虑在您的表上提供 SHOW CREATE TABLE ),我无法确定:

SELECT film.*
FROM (film)
LEFT JOIN film_rating_report ON film.filmid = film_rating_report.filmid AND film_rating_report.rating = 'GE'
WHERE film_rating_report.filmid IS NOT NULL
GROUP BY film.filmid

WHERE film_rating_report.filmid IS NOT NULL可防止没有您正在寻找的评级的行偷偷进入,我在最后添加了GROUP BY因为film_rating_report可能匹配不止一次 - 不确定因为我可以看到存储的数据在里面)

于 2013-07-01T08:13:03.900 回答