简体   繁体   English

具有多个条件的 SQL WHERE 语句

[英]SQL WHERE statement with multiple conditions

I have a movies, credits, people and roles table (below) I would like to find the names of the people who are both actors and directors.我有一个电影、演职员表、人物和角色表(如下)我想找到既是演员又是导演的人的名字。

movies(TABLE)电影(表格)

id int
title

credits(TABLE)学分(表格)

id int
movie_id int
person_id int
role_id int

people(TABLE)人(桌子)

id int
name

roles(TABLE)角色(表格)

id int
role    (Actor, Director)

This is what I have did:这就是我所做的:

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

However, I am getting 0 results.但是,我得到 0 结果。 Any suggestion is appreciated.任何建议表示赞赏。

The problem is that there's no single row in the resulting table whose 'role' is both 'Director' and 'Actor', because 'role' can only be one value.问题是结果表中没有一行的 'role' 既是 'Director' 又是 'Actor',因为 'role' 只能是一个值。

It's useful to first think of what your table looks like after your joins.首先考虑联接后表的外观很有用。 In this case, you have:在这种情况下,您有:

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

Now a person who is both director and actor will have two rows in this table, like this:现在一个既是导演又是演员的人在这个表中会有两行,像这样:

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

As others have said, you need to either perform an aggregation so one row can have multiple role values, or you can get the result and filter externally正如其他人所说,您需要执行聚合以便一行可以有多个角色值,或者您可以获得结果并在外部进行过滤

I think you want aggregation:我想你想要聚合:

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;

The problem with your query is that you are searching for a single role that is both Director and Actor: both conditions cannot be true at the same time, so the query comes up empty.您的查询的问题在于您正在搜索既是导演又是演员的单个角色:两个条件不能同时为真,因此查询结果为空。

Whenever you need to look across multiple rows, aggregation comes to mind:每当您需要查看多行时,就会想到聚合:

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

This searches for persons that are Director or Actor, then groups rows by person;这将搜索作为导演演员的人,然后按人对行进行分组; finally, the having clause allows only persons that have both roles.最后, having条款只允许有两个角色的人。

There are two answers that use the same method, but both are wrong.有两个答案使用相同的方法,但都是错误的。 If this hypothetical database contains only a single movie per person, then it will work out.如果这个假设的数据库每人只包含一部电影,那么它就会成功。 If there are multiple movies where a people record is referenced, or if a single people record is referenced by credits joined to roles records of roles .如果出现其中多部影片people的记录被引用,或者如果一个people记录被引用的credits加入到roles的记录roles role = 'Director' or roles . role = '导演' 或roles role = 'Actor`, this query returns a record for that invalid result. role = 'Actor`,此查询返回该无效结果的记录。 This breaks the specified behavior.这会破坏指定的行为。

Note that @Jason-Chen explains the issue you're experiencing with your query, while I'm specifically contradicting the two answers with solutions given as of the posting-time.请注意,@Jason-Chen 解释了您在查询中遇到的问题,而我在发布时给出的解决方案中特别反驳了这两个答案。

Instead of simply counting the results to guarantee more than one role per people.id, which is the only guarantee the above two examples give, the admin should instead query for a connection that exists both in the list of all roles records where 'Director' is the roles.role value and all records where 'Actor' is the roles.role value.不是简单地计算结果以保证每个 people.id 有多个角色,这是上面两个示例给出的唯一保证,管理员应该查询存在于“Director”的所有角色记录列表中的连接是roles.role 值和“Actor”是roles.role 值的所有记录。

Note that I use different names below, because I generally find the practice of single-letter aliases to be awful, and I wish instructors would instill better practices in new students.请注意,我在下面使用了不同的名称,因为我通常认为单字母别名的做法很糟糕,我希望教师能够向新学生灌输更好的做法。 Further, I find that table names in singular form yield the most readable code.此外,我发现单数形式的表名产生最易读的代码。

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

I'm selecting a single value from both of the sub-queries on the roles table, which does not require an alias and instead behaves as a set.我从角色表上的两个子查询中选择一个值,它不需要别名,而是作为一个集合。 This results in very quick lookups, even for rather large tables, provided the keys used are indexed on both sides of the join.这会导致非常快速的查找,即使对于相当大的表,只要使用的键在连接的两侧都有索引。

Further, this is better than a join, because given real life examples like "Keanu Reaves", "Mel Gibson," "Tom Cruise," or other celebrities that have many Director/Actor movies under their belt, each such record would result in resultset magnification, where a single added record in data causes more than one resulting record.此外,这比加入更好,因为考虑到现实生活中的例子,如“基努里维斯”、“梅尔吉布森”、“汤姆克鲁斯”或其他拥有许多导演/演员电影的名人,每一个这样的记录都会导致结果集放大,其中数据中的单个添加记录会导致多个结果记录。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM