mysql - 如何将 NOT IN 子查询重写为连接

标签 mysql sql join subquery

假设 MySQL 中的下表描述了文件夹中包含的文档。

mysql> select * from folder;
+----+----------------+
| ID | PATH           |
+----+----------------+
|  1 | matches/1      |
|  2 | matches/2      |
|  3 | shared/3       |
|  4 | no/match/4     |
|  5 | unreferenced/5 |
+----+----------------+


mysql> select * from DOC;
+----+------+------------+
| ID | F_ID | DATE       |
+----+------+------------+
|  1 |    1 | 2000-01-01 |
|  2 |    2 | 2000-01-02 |
|  3 |    2 | 2000-01-03 |
|  4 |    3 | 2000-01-04 |
|  5 |    3 | 2000-01-05 |
|  6 |    3 | 2000-01-06 |
|  7 |    4 | 2000-01-07 |
|  8 |    4 | 2000-01-08 |
|  9 |    4 | 2000-01-09 |
| 10 |    4 | 2000-01-10 |
+----+------+------------+

列ID是主键,表DOC的列F_ID是引用表FOLDER主键的非空外键。通过在 where 子句中使用文档的“DATE”,我想找到哪些文件夹只包含选定的文档。对于早于 2000-01-05 的文档,这可以写成:

SELECT DISTINCT d1.F_ID 
FROM DOC d1 
WHERE d1.DATE < '2000-01-05' 
AND d1.F_ID NOT IN (
    SELECT d2.F_ID 
    FROM DOC d2 WHERE NOT (d2.DATE < '2000-01-05')
);

并且它正确返回“1”和“2”。通过阅读 http://dev.mysql.com/doc/refman/5.5/en/rewriting-subqueries.html 如果将子查询替换为连接,则可以提高大表的性能。我已经找到了与 NOT IN 和 JOINS 相关的问题,但并不完全是我想要的。那么,关于如何使用连接编写它有什么想法吗?

最佳答案

一般的答案是:

select t.*
from t
where t.id not in (select id from s)

可以重写为:

select t.*
from t left outer join
     (select distinct id from s) s
     on t.id = s.id
where s.id is null

我认为您可以将此应用于您的情况。

关于mysql - 如何将 NOT IN 子查询重写为连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10592554/

相关文章:

mysql - 从具有给定条件的一个表中选择不同类型的多行,如果未找到,则选择下一个可能的行

MySQL 慢查询 ~ 10 秒

php - 如何查询5分钟内插入2次以上,邮箱地址相同,status=1的重复记录?

c# - 我应该学习哪些概念来实现这一点?

mysql - 根据 child 及其 child 的条件获取父数据

mysql - 在mysql中使用内连接将列转换为行

sql - 将 SQL 结果分组/聚合到 1 小时的桶中

sql - 如何使用 join 和 where 子句从另一表中仅删除一个表中的值

sql - 在sqlite中将子查询转换为左联接

mysql - 将日期时间与字符串进行比较时非法混合排序规则