问题描述
我有一个电影,片名,人物和角色表(如下),我想找到既是演员又是导演的人的名字。
电影(表格)
id int
title
积分(表格)
id int
movie_id int
person_id int
role_id int
people(TABLE)
id int
name
角色(表格)
id int
role (Actor,Director)
这就是我所做的:
SELECT p.name,r.role,m.role_id
FROM mtm_credits m
JOIN people p ON p.id = m.person_id
JOIN roles r ON r.id = m.role_id
WHERE role = 'Director' AND role = 'Actor';
但是,我得到0条结果。任何建议表示赞赏。
解决方法
问题在于结果表中没有一行“角色”既是“导演”又是“演员”的行,因为“角色”只能是一个值。
在联接后首先考虑表的外观很有用。在这种情况下,您可以:
credits.id,credits.movie_id,credits.person_id,credits.role_id,person.id,person.name,role.id,role.name
现在既是导演又是演员的人在此表中将有两行,如下所示:
| credits.id | credits.movie_id | credits.person_id | credits.role_id | person.id | person.name | role.id | role.name |
| 111 | 222 | 333 | 444 | 555 | 333 | N. Cage | 555 | Actor |
| 111 | 222 | 333 | 444 | 555 | 333 | N. Cage | 555 | Director |
正如其他人所说,您需要执行聚合,以便一行可以具有多个角色值,或者您可以获取结果并在外部进行过滤
,我认为您想要汇总:
SELECT p.name
FROM mtm_credits m JOIN
people p
ON p.id = m.person_id JOIN
roles r
ON r.id = m.role_id
WHERE r.role IN ('Director','Actor')
HAVING COUNT(DISTINCT r.role) = 2;
,
查询的问题是您要搜索一个既是导演又是演员的角色:两个条件不能同时满足,因此查询为空。
每当您需要查看多行时,就会想到聚合:
SELECT p.*
FROM mtm_credits m
JOIN people p ON p.id = m.person_id
JOIN roles r ON r.id = m.role_id
WHERE r.role IN ('Director','Actor')
GROUP BY p.id
HAVING COUNT(DISTINCT r.role) = 2
这会搜索作为导演或演员的人员,然后按人员对行进行分组;最后,having
子句只允许同时担任这两种角色的人。
有两个答案使用相同的方法,但是都错了。如果这个假设的数据库每人只包含一部电影,那么它将成功。如果有多个电影引用了people
记录,或者如果people
引用了一个credits
记录,而roles
的{{1}}记录中又加入了{。 {1}} ='导演'或roles
。role
='演员',此查询返回该无效结果的记录。这会破坏指定的行为。
请注意,@ Jason-Chen解释了您在查询中遇到的问题,而我在发布时给出的解决方案特别矛盾了这两个答案。
管理员不应该简单地计算结果以确保每个人具有多个角色,这是上述两个示例唯一的保证,管理员应该查询所有角色记录列表中都存在的连接,其中“导演”是roles.role值,以及所有记录,其中“演员”是roles.role值。
请注意,我在下面使用了不同的名称,因为我通常会发现单字母别名的做法很糟糕,我希望教师能为新生提供更好的做法。此外,我发现单数形式的表名产生的代码可读性最高。
roles
我正在从角色表的两个子查询中选择一个值,该值不需要别名,而是表现为一个集合。只要使用的键在连接的两面都建立索引,即使对于相当大的表,也可以非常快速地进行查找。
此外,这比联接更好,因为给定现实生活中的示例,例如“基努·里夫斯”,“梅尔·吉布森”,“汤姆·克鲁斯”或其他名人,其中很多导演/演员电影都在他们的指挥之下,每条这样的记录将导致结果集放大,其中在数据中添加一条记录会导致多个结果记录。