SQL:如何在一个 table 中查找没有引用另一个 table 中的行的行?
SQL: How to find rows in one table that have no references to rows in another tables?
我有三个 table:users
、rooms
、room_users
。
用户可以有很多房间,房间也可以有很多用户,所以这是多对多的关系。
users
table:
+----+-----------+-----+
| id | name | age |
+----+-----------+-----+
| 1 | Christian | 19 |
| 2 | Ben | 36 |
| 3 | Robert | 52 |
| 4 | Monica | 25 |
| 5 | Alice | 26 |
| 6 | William | 18 |
+----+-----------+-----+
rooms
table:
+----+----------+
| id | name |
+----+----------+
| 1 | College |
| 2 | Work |
| 3 | Football |
+----+----------+
和room_users
table表示用户和房间的关系:
+---------+---------+
| user_id | room_id |
+---------+---------+
| 1 | 1 |
| 1 | 3 |
| 2 | 2 |
| 4 | 1 |
| 5 | 2 |
| 6 | 1 |
| 6 | 3 |
+---------+---------+
所以,有了这些 tables 我们可以说:
- Christian(1) 属于 College(1) 和 Football(3) 房间。
- Ben(2) 属于 Work(2) 房间。
- 罗伯特(3)不属于任何房间。
- Monica(4) 属于 College(1) 房间。
- Alice(5) 属于 Work(2) 房间。
- William(1) 属于 College(1) 和 Football(3) 房间。
现在,如果我想查找确实属于足球室的用户 (id),我应该使用此查询:
SELECT user_id FROM room_users WHERE room_id = 3
此查询的输出:
+---------+
| user_id |
+---------+
| 1 |
| 6 |
+---------+
这是正确的,只有 Christian(1) 和 William(3) 属于足球室。
但是如何找到不属于足球房的用户呢?
在这种情况下,查询必须 return 2、3、4 和 5 个 ID。即除第一个查询的ID外的所有ID。
是否可以使用 LEFT JOIN
来实现?
据我所知,它比使用子查询更有效。
提前致谢!
编辑:
我找到了可以解决问题的查询,但是这个查询在大型数据库上非常慢:
SELECT users.id FROM users WHERE 0=(SELECT COUNT(*) FROM room_users WHERE user_id=users.id AND room_id=3);
没有相关行为,尝试这样的事情:
SELECT u.*
FROM users AS u
LEFT JOIN (
SELECT DISTINCT user_id FROM room_users WHERE room_id = 3
) AS v
ON v.user_id = u.id
WHERE v.user_id IS NULL
;
对于性能问题,请先查看 explain/execution 计划和索引的使用。
您可以找到那些属于足球室的用户,然后排除那些使用不在的用户。
您也可以使用 JOIN
SELECT u.*
FROM
users u
WHERE user_id NOT IN
(SELECT user_id FROM room_users WHERE room_id=3)
你说得对,这可以用左连接来完成。
SELECT
u.id
FROM
users u
LEFT JOIN room_users ur
ON u.id = ur.user_id
AND ur.room_id = 3
WHERE
ur.room_id is null;
我有三个 table:users
、rooms
、room_users
。
用户可以有很多房间,房间也可以有很多用户,所以这是多对多的关系。
users
table:
+----+-----------+-----+
| id | name | age |
+----+-----------+-----+
| 1 | Christian | 19 |
| 2 | Ben | 36 |
| 3 | Robert | 52 |
| 4 | Monica | 25 |
| 5 | Alice | 26 |
| 6 | William | 18 |
+----+-----------+-----+
rooms
table:
+----+----------+
| id | name |
+----+----------+
| 1 | College |
| 2 | Work |
| 3 | Football |
+----+----------+
和room_users
table表示用户和房间的关系:
+---------+---------+
| user_id | room_id |
+---------+---------+
| 1 | 1 |
| 1 | 3 |
| 2 | 2 |
| 4 | 1 |
| 5 | 2 |
| 6 | 1 |
| 6 | 3 |
+---------+---------+
所以,有了这些 tables 我们可以说:
- Christian(1) 属于 College(1) 和 Football(3) 房间。
- Ben(2) 属于 Work(2) 房间。
- 罗伯特(3)不属于任何房间。
- Monica(4) 属于 College(1) 房间。
- Alice(5) 属于 Work(2) 房间。
- William(1) 属于 College(1) 和 Football(3) 房间。
现在,如果我想查找确实属于足球室的用户 (id),我应该使用此查询:
SELECT user_id FROM room_users WHERE room_id = 3
此查询的输出:
+---------+
| user_id |
+---------+
| 1 |
| 6 |
+---------+
这是正确的,只有 Christian(1) 和 William(3) 属于足球室。
但是如何找到不属于足球房的用户呢? 在这种情况下,查询必须 return 2、3、4 和 5 个 ID。即除第一个查询的ID外的所有ID。
是否可以使用 LEFT JOIN
来实现?
据我所知,它比使用子查询更有效。
提前致谢!
编辑:
我找到了可以解决问题的查询,但是这个查询在大型数据库上非常慢:
SELECT users.id FROM users WHERE 0=(SELECT COUNT(*) FROM room_users WHERE user_id=users.id AND room_id=3);
没有相关行为,尝试这样的事情:
SELECT u.*
FROM users AS u
LEFT JOIN (
SELECT DISTINCT user_id FROM room_users WHERE room_id = 3
) AS v
ON v.user_id = u.id
WHERE v.user_id IS NULL
;
对于性能问题,请先查看 explain/execution 计划和索引的使用。
您可以找到那些属于足球室的用户,然后排除那些使用不在的用户。 您也可以使用 JOIN
SELECT u.*
FROM
users u
WHERE user_id NOT IN
(SELECT user_id FROM room_users WHERE room_id=3)
你说得对,这可以用左连接来完成。
SELECT
u.id
FROM
users u
LEFT JOIN room_users ur
ON u.id = ur.user_id
AND ur.room_id = 3
WHERE
ur.room_id is null;