【问题标题】:SQL WHERE statement with multiple conditions具有多个条件的 SQL WHERE 语句
【发布时间】:2020-12-13 13:31:33
【问题描述】:

我有一个电影、演职员表、人物和角色表(如下),我想查找既是演员又是导演的人的姓名。

电影(表格)

id int
title

学分(表)

id int
movie_id int
person_id int
role_id int

人(表)

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

【问题讨论】:

  • 显示一些示例数据和预期结果。
  • role 怎么可能同时是DirectorActor?根据您需要加入角色表两次或需要使用OR(或IN)而不是AND
  • 请只标记一个RDBMS,MySQL和SQL Server是不同的产品。
  • 请在代码问题中给出minimal reproducible example--cut & paste & runnable code,包括最小的代表性示例输入作为代码;期望和实际输出(包括逐字错误消息);标签和版本;明确的规范和解释。给出尽可能少的代码,即您显示的代码可以通过您显示的代码扩展为不正常的代码。 (调试基础。)对于包含 DBMS 和 DDL(包括约束和索引)和输入为格式化为表的代码的 SQL。 How to Ask 暂停总体目标的工作,将代码砍到第一个表达式,没有给出你期望的内容,说出你期望的内容和原因。
  • 您的总体目标是一个常见问题解答。请在考虑发布之前阅读您的教科书和/或手册和谷歌任何错误消息或您的问题/问题/目标的许多清晰、简洁和精确的措辞,有和没有您的特定字符串/名称和站点:*.com 和标签;阅读许多答案。如果您发布问题,请使用一个短语作为标题。反映你的研究。请参阅How to Ask 和投票箭头鼠标悬停文本。

标签: mysql sql join where-clause having-clause


【解决方案1】:

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

请注意,@Jason-Chen 解释了您在查询时遇到的问题,而我特意将这两个答案与发布时给出的解决方案相矛盾。

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

请注意,我在下面使用了不同的名称,因为我通常认为单字母别名的做法很糟糕,我希望教师能够向新生灌输更好的做法。此外,我发现单数形式的表名产生的代码可读性最强。

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"
);

我从角色表上的两个子查询中选择一个值,它不需要别名而是表现为一个集合。这会导致非常快速的查找,即使对于相当大的表,只要使用的键在连接的两侧都有索引。

此外,这比加入要好,因为现实生活中的例子,如“基努·里夫斯”、“梅尔·吉布森”、“汤姆·克鲁斯”或其他名人,他们拥有许多导演/演员电影,每一个这样的记录会导致结果集放大,其中在数据中添加一条记录会导致多条结果记录。

【讨论】:

    【解决方案2】:

    问题是结果表中没有一行“角色”既是“导演”又是“演员”,因为“角色”只能是一个值。

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

    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 |
    

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

    【讨论】:

      【解决方案3】:

      您的查询的问题是您正在搜索一个既是导演又是演员的角色:这两个条件不能同时为真,因此查询为空。

      每当您需要查看多行时,就会想到聚合:

      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 子句只允许同时担任这两个角色的人。

      【讨论】:

      • 假设一个演员在电影中扮演多个角色,但不是导演。像戴夫·迪格斯这样的人将作为有效结果返回,因为他在汉密尔顿的表现,作为拉斐特和杰斐逊,但不是导演。给定的查询不会区分该结果的质量和 Keanu Reaves 或 Nicholas Cage 的结果的质量。
      【解决方案4】:

      我想你想要聚合:

      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;
      

      【讨论】:

      • 我也评论了一个不同的答案,但此查询中没有步骤来区分同一部电影中扮演多个角色的演员。在给定的示例中,它可能非常有效,因为“字符”不是角色表上的字段,但在更贴近生活的示例中,这会产生不希望的行为。
      • @SamHughes 。 . .问题不在于一个人是否在同一部电影中同时扮演两个角色。
      • ....嗯,你是对的。通过将其转化为现实世界的解决方案,我使我的阅读变得过于复杂。假设只有两个可能的角色值,由 OP 指定,那么这就完成了所需的输出。
      最近更新 更多