SQL - 列出与其他人一起显示的属性

时间:2014-10-30 02:58:25

标签: mysql sql

我正在完成一项任务,要求我列出电影中出现的演员和女演员,然后是在其他电影中出演的演员和女演员。可在此处查看数据库图表:http://i.imgur.com/kj8qVgF.png

我对第一部分有一个查询(获取某部电影中出现的演员和女演员的姓名)。

SELECT DISTINCT n.name
FROM cast_info c
INNER JOIN name n
ON (n.id = c.person_id)
INNER JOIN title t
ON (c.movie_id = t.id)
CROSS JOIN role_type r
WHERE (t.title = 'The Movie') AND (r.role = 'actress' OR r.role = 'actor')

我是否可以帮助我找到在其他电影中与他们一起演出的女演员和演员?

示例:

Actors in a given movie 'The Movie': Bob, Joe, Billy 
Actors in a different movie 'Another Movie': Joe, Daniel, Frank
Actors in another different movie 'Third Movie': Billy, Susan, Theodore

它应该归还丹尼尔,弗兰克,苏珊和西奥多,因为他们与给定电影中的一位演员一起出演了至少一部电影。

2 个答案:

答案 0 :(得分:1)

根据您的示例,您的模型是3NF,因此您可以使用简单的IN来解决问题,就像您在自然语言中所描述的那样。

SELECT DISTINCT n.name
FROM cast_info c
INNER JOIN name n
ON (n.id = c.person_id)
INNER JOIN title t
ON (c.movie_id = t.id)
INNER JOIN role_type r
ON (c.role_id = r.id)
WHERE (r.role = 'actress' OR r.role = 'actor')  --  find the actresses and actors ...
AND c.movie_id IN          -- starred in at least one movie  ...
    (SELECT movie_id  
     FROM cast_info
     WHERE id in          -- with one of the actors in the given movie => Bob, Joe, Billy 
        (SELECT cc.id
         FROM cast_info cc
         INNER JOIN role_type rr
         ON (cc.role_id = rr.id)
         WHERE ( rr.role = 'actor') -- only select actors in the given movie
         AND cc.movie_id in (select id from title where title = 'The Movie') 
        )
    )
AND c.id NOT IN  -- except the actors in the given movie
        (SELECT cc.id
         FROM cast_info cc
         INNER JOIN role_type rr
         ON (cc.role_id = rr.id)
         WHERE ( rr.role = 'actor') -- only select actors in the given movie
         AND cc.movie_id in (select id from title where title = 'The Movie') 
        )

这很容易将自然语言翻译为SQL但使用IN效率不高,您可以使用IN转移EXISTS,这会更有效。

答案 1 :(得分:1)

所以我们再见面。希望我能提供与你上一个问题相同的帮助。我喜欢你开始把它分成更小的部分。我会和你在同一个地方开始 - 让所有演员都参与到必要的电影中。我稍微改变了你的查询,通过选择人员ID而不是他们的名字,这样我就可以让这个答案更短更清洁。

SELECT c.person_id
FROM cast_info c
JOIN title t ON c.movie_id = t.id
JOIN role_type r ON c.role_id = r.id
WHERE t.title = 'The Movie' AND (r.role = 'actress' OR r.role = 'actor');

*请注意,我没有在这里使用distinct,因为一个人不应该多次出现在这部电影中作为演员或女演员,但是c.person_id不是一个独特的键,所以不会有任何伤害。

然后我们就可以获得所有这些演员的电影。我们可以过滤以避免原始表。

SELECT t.id
FROM title t
JOIN cast_info c ON c.movie_id = t.id
WHERE t.title != 'The Movie'
   AND c.person_id IN(SELECT c.person_id
                         FROM cast_info c
                         JOIN title t ON c.movie_id = t.id
                         JOIN role_type r ON r.id = c.role_id
                         WHERE t.title = 'The Movie' AND (r.role = 'actress' OR r.role = 'actor'))

现在我们可以从所有这些电影中拉出所有演员,并排除我们原来的演员。这是使用不同的人ID的好主意。这是因为鲍勃可能会出演“电影”。后来,鲍勃与约翰一起拍了一部电影,又和约翰一起拍了一部电影,但我们不希望约翰出现两次。

所以,这是最终的查询:

SELECT DISTINCT c.person_id
FROM cast_info c
WHERE c.movie_id IN(SELECT t.id
                 FROM title t
                 JOIN cast_info c ON c.movie_id = t.id
                 WHERE t.title != 'The Movie'
                    AND c.person_id IN(SELECT c.person_id
                                      FROM cast_info c
                                      JOIN title t ON c.movie_id = t.id
                                      JOIN role_type r ON r.id = c.role_id
                                      WHERE t.title = 'The Movie' AND (r.role = 'actress' OR r.role = 'actor')))
   AND c.person_id NOT IN(SELECT c.person_id
                         FROM cast_info c
                         JOIN title t ON c.movie_id = t.id
                         JOIN role_type r ON r.id = c.role_id
                         WHERE t.title = 'The Movie' AND (r.role = 'actress' OR r.role = 'actor'))

正如我之前所说的那样,没有数据就很难对它进行测试,而且制作一个简单的SQL小提琴会有很多表格,所以如果它们不起作用的话,请像我写的一样尝试这些,以及让我知道可能需要调整的内容。