【问题标题】:SQL query records containing all items in list包含列表中所有项目的 SQL 查询记录
【发布时间】:2014-06-27 23:24:49
【问题描述】:

我有以下表格:

电影

MOVIE_ID 标题 ---------- ----------------- 1 肖申克的救赎 2 教父 3 教父:第二部分 4 黑暗骑士 5 低俗小说 6 好,坏,丑 7 辛德勒的名单 8 愤怒的男人 9 搏击俱乐部 10 开始 11 阿甘正传

董事

DIRECTOR_ID 名称 ------------ ------------- 1 蒂姆·罗宾斯 2 摩根弗里曼 3 马龙白兰度 4 阿尔帕基诺 5 罗伯特·德尼罗 6 克里斯蒂安·贝尔 7 希斯莱杰 8 约翰·特拉沃拉 9 乌玛·瑟曼 10 克林特·伊斯特伍德 11 伊莱·瓦拉赫

直接

MOVIE_ID DIRECTOR_ID ---------- ------------ 1 1 1 2 2 3 2 4 3 4 3 5 4 6 4 7 5 8 5 9 6 10

我想要一个返回所有以 x、y 和 z 作为导演的电影的查询:

例子:

如果我要找一部有 Al PachinoClint Eastwood 的电影,它 应该返回 nothing 因为我没有一部同时具有这两者的电影 他们是导演。

但是,如果我要找一部与 Tim RobbinsMorgan 合作的电影 弗里曼,它应该返回肖申克的救赎

如果使用上述设计无法完成,请提出替代方案。

我已经尝试过了,但我的查询会返回结果:(

SELECT m.title FROM Movie m 
WHERE m.movie_id IN (
      SELECT d.movie_id FROM Direct d
      WHERE d.director_id IN (
           SELECT director_id FROM Director dir 
           WHERE name IN('Clint Eastwood', 'Al Pachino')));

【问题讨论】:

    标签: mysql sql oracle sqlite relational-division


    【解决方案1】:

    这是实现这一目标的一种方法,即对董事进行分组、过滤然后计数:

    SELECT m.title 
    FROM Movie m
         INNER JOIN Direct md
         on md.movie_id = m.movie_id
         INNER JOIN Directors d
         on md.director_id = d.director_id
    WHERE 
         d.name IN('Clint Eastwood', 'Al Pachino')
    GROUP BY m.title
    HAVING COUNT(DISTINCT d.director_id) = 2;
    

    SqlFiddle here

    {出于兴趣,这些不是电影里的演员吗?}

    【讨论】:

    • 这只是为了说明目的
    • 在没有导演可以两次导演同一部电影的基础上,DISTINCT运算符应该是多余的
    • @Strawberry 嗯……也许是导演剪辑版的重新发行?更严重的是,OP 没有发布 DDL,所以没有 UNIQUE KEY 或 PK 约束,比抱歉更安全 ;-)
    【解决方案2】:

    使用 IN 运算符,您的查询将返回包含任何这些导演的电影。

    您必须分别检查每个导演:

    SELECT *
    FROM Movie
    WHERE movie_id IN (SELECT movie_id
                       FROM Direct
                       WHERE director_id = (SELECT director_id
                                            FROM Directors
                                            WHERE name = 'Clint Eastwood'))
      AND movie_id IN (SELECT movie_id
                       FROM Direct
                       WHERE director_id = (SELECT director_id
                                            FROM Directors
                                            WHERE name = 'Al Pachino'))
    

    或者,使用compound query 为两位导演构建电影 ID 列表:

    SELECT *
    FROM Movie
    WHERE movie_id IN (SELECT movie_id
                       FROM Direct
                       WHERE director_id = (SELECT director_id
                                            FROM Directors
                                            WHERE name = 'Clint Eastwood')
                       INTERSECT
                       SELECT movie_id
                       FROM Direct
                       WHERE director_id = (SELECT director_id
                                            FROM Directors
                                            WHERE name = 'Al Pachino'))
    

    或者,从Direct 表中获取这两个导演的所有记录,然后按电影分组,以便能够计算每部电影的导演;我们需要剩下两个:

    SELECT *
    FROM Movie
    WHERE movie_id IN (SELECT movie_id
                       FROM Direct
                       WHERE director_id IN (SELECT director_id
                                             FROM Directors
                                             WHERE name IN ('Clint Eastwood',
                                                            'Al Pachino')
                       GROUP BY movie_id
                       HAVING COUNT(*) = 2)
    

    【讨论】:

      【解决方案3】:

      最短的

         ;with cte as (      
          select m.title, ROW_NUMBER() over (partition by m.title order by dir.name) rn 
          from Movie m
          inner join Direct d on m.movie_id = d.movie_id
          inner join Director dir on dir.DIRECTOR_ID = d.director_id
          where dir.name IN ('Clint Eastwood', 'Al Pachino')
          )
          select * from cte where rn > 1
      

      【讨论】:

        【解决方案4】:

        你也可以用 SQLite 试试:

        SELECT title
         FROM movie NATURAL JOIN direct NATURAL JOIN directors
         GROUP BY title
          HAVING GROUP_CONCAT(name)  LIKE '%Morgan Freeman%' AND GROUP_CONCAT(name)  LIKE '%Tim  Robbins%'
        ;
        

        测试here

        【讨论】:

          猜你喜欢
          • 2019-10-12
          • 2017-10-18
          • 1970-01-01
          • 2019-03-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-12-26
          相关资源
          最近更新 更多