SQL 具有多个条件的 WHERE 语句

SQL WHERE statement with multiple conditions

我有电影、演职员表、人物和角色table(下)我想找到既是演员又是导演的人的名字。

电影(TABLE)

id int
title

学分(TABLE)

id int
movie_id int
person_id int
role_id int

人(TABLE)

id int
name

角色(TABLE)

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 个结果。任何建议表示赞赏。

我想你想要聚合:

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 子句只允许同时具有这两种角色的人。

问题是结果 table 中没有一行 'role' 既是 'Director' 又是 'Actor',因为 'role' 只能是一个值。

首先考虑您的 table 加入后的样子是很有用的。在这种情况下,您有:

credits.id, credits.movie_id, credits.person_id, credits.role_id, person.id, person.name, role.id, role.name

现在一个既是导演又是演员的人在这个table中会有两行,像这样:

| 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 |

正如其他人所说,您需要执行聚合以便一行可以有多个角色值,或者您可以获取结果并在外部进行过滤

有两个答案使用相同的方法,但都是错误的。如果这个假设的数据库只包含每个人一部电影,那么它就会成功。如果有多部电影引用了 people 记录,或者如果 credits 引用了单个 people 记录并加入了 rolesroles 记录。role = 'Director' 或 roles.role = 'Actor`,此查询 returns 该无效结果的记录。这会破坏指定的行为。

请注意,@Jason-Chen 解释了您在查询时遇到的问题,而我特别反对这两个答案与 posting-time.

时给出的解决方案

与其简单地计算结果以保证每个 people.id 有多个角色,这是上述两个示例给出的唯一保证,管理员应该查询同时存在于列表中的连接'Director' 是 roles.role 值的所有角色记录和 'Actor' 是 roles.role 值的所有记录。

请注意,我在下面使用了不同的名称,因为我通常发现 single-letter 别名的做法很糟糕,我希望教师能向新学生灌输更好的做法。此外,我发现 table 单数形式的名称产生最易读的代码。

select `person`.*
from `people` `person`
where `person`.`id` in (
    select `credit`.`person_id`
    from `roles` `role`
    join`credits` `credit`
        on `role`.`id` = `credit`.`role_id`
    where `role` like "Director" 
) and `person`.`id` in (
    select `credit`.`person_id`
    from `roles` `role`
    join`credits` `credit`
        on `role`.`id` = `credit`.`role_id`
    where `role` like "Actor"
);

我从角色 table 的两个 sub-queries 中选择一个值,它不需要别名,而是作为一个集合。这会导致非常快速的查找,即使对于相当大的 tables,前提是所使用的键在连接的两侧都有索引。

此外,这比连接更好,因为给出现实生活中的例子,例如“基努·里维斯”、“梅尔·吉布森”、“汤姆·克鲁斯”或其他拥有许多 Director/Actor 电影的名人,每个这样的记录都会导致结果集放大,其中数据中的单个添加记录会导致多个结果记录。