正确连接多个多对多表-MySQL查询

正确连接多个多对多表-MySQL查询,mysql,sql,join,subquery,having-clause,Mysql,Sql,Join,Subquery,Having Clause,一个看似通用的SQL查询真的让我不知所措。 情况是这样的。 我有3个通用表(此处为简化版): 和2个多对多表来连接它们: Movie_Genre movie_id | genre_id Movie_Rating movie_id | rating_id 最初的挑战是编写一个查询,允许我获取属于多种类型(例如恐怖喜剧或科幻动作)的电影 谢天谢地,我在这里找到了这个解决方案 但是,获取属于多对多表的记录的正确选项是什么?例如,评级为R级的恐怖喜剧。有没有办法不用子查询(或只使用一个子查询

一个看似通用的SQL查询真的让我不知所措。 情况是这样的。 我有3个通用表(此处为简化版):

和2个多对多表来连接它们:

Movie_Genre

movie_id | genre_id


Movie_Rating

movie_id | rating_id
最初的挑战是编写一个查询,允许我获取属于多种类型(例如恐怖喜剧或科幻动作)的电影

谢天谢地,我在这里找到了这个解决方案


但是,获取属于多对多表的记录的正确选项是什么?例如,评级为R级的恐怖喜剧。有没有办法不用子查询(或只使用一个子查询)就可以这样做?

一种方法使用相关子查询:

select m.*
from movies m
where (select count(*)
       from movie_genre mg
       where mg.movie_id = m.id
      ) > 1 and
      (select count(*)
       from movie_rating mr
       where mr.movie_id = m.id
      ) > 1 ;
select m.*
from movie m
where
    exists (
        select 1 
        from movie_genre mg
        inner join genre g on g.id = mg.genre_id
        where mg.movie_id = m.id and g.title = 'R')
    and exists (
        select 1
        from movie_rating mr
        inner join rating r on r.id = mr.rating_id
        where mr.movie_id = m.id and r.title = 'Horror'
    )
    and exists (
        select 1
        from movie_rating mr
        inner join rating r on r.id = mr.rating_id
        where mr.movie_id = m.id and r.title = 'Comedy'
    )
通过
movie\u流派(movie\u id)
movie\u评级(movie\u id)
上的索引,这可能具有相当合理的性能

上述方法可能是最有效的方法。但是,如果希望避免子查询,一种方法是:

select mg.movie_id
from movie_genres mg join
     movie_ratings mr
     on mg.movie_id = mr.movie_id
group by mg.movie_id
having count(distinct mg.genre_id) > 0 and
       count(distinct mr.genre_id) > 0;
比上述方法更有效的是在
加入之前进行聚合

select mg.movie_id
from (select movie_id
      from mg_genres
      group by movie_id
      having count(*) >= 2
     ) mg join
     (select movie_id
      from mg_ratings
      group by movie_id
      having count(*) >= 2
     ) mr
     on mg.movie_id = mr.movie_id;
尽管您声明希望避免子查询,但讽刺的是,没有子查询的版本可能在这三个选项中性能最差

例如,评级为R级的恐怖喜剧

您可以
将所有表连接在一起,按电影进行聚合,并使用
HAVING
子句进行筛选:

select m.id, m.title
from movies m
inner join movie_genre  mg on mg.movid_id = m.id
inner join genre g on g.id = mg.genre_id
inner join movie_rating mr on mr.movie_id = m.id
inner join rating r on r.id = mr.rating_id
group by m.id, m.title
having 
    max(r.title = 'R') = 1 
    and max(g.title = 'Horror') = 1
    and max(g.title = 'Comedy') = 1
您还可以使用两个
exists
条件以及相关子查询:

select m.*
from movies m
where (select count(*)
       from movie_genre mg
       where mg.movie_id = m.id
      ) > 1 and
      (select count(*)
       from movie_rating mr
       where mr.movie_id = m.id
      ) > 1 ;
select m.*
from movie m
where
    exists (
        select 1 
        from movie_genre mg
        inner join genre g on g.id = mg.genre_id
        where mg.movie_id = m.id and g.title = 'R')
    and exists (
        select 1
        from movie_rating mr
        inner join rating r on r.id = mr.rating_id
        where mr.movie_id = m.id and r.title = 'Horror'
    )
    and exists (
        select 1
        from movie_rating mr
        inner join rating r on r.id = mr.rating_id
        where mr.movie_id = m.id and r.title = 'Comedy'
    )

为什么有两张多对多的桌子?谢谢你的最新版本!它也将很好地融入代码中!