MySQL“ NOT IN”查询


181

我想运行一个简单的查询,以抛出所有Table1其他表(Table2)的列中不存在主体列值的行。

我尝试使用:

SELECT * FROM Table1 WHERE Table1.principal NOT IN Table2.principal

而是抛出语法错误。Google搜索使我进入了一个论坛,那里的人们说MySQL不支持NOT IN,因此需要使用极其复杂的东西。这是真的?还是我犯了一个可怕的错误?


1
如果我要从三个表中获得相似的数据怎么办?我的意思是一个表1有2000个条目,其他两个表2&3每个都有500个条目,它们都有共同的字段“名称”。我们如何基于“名称”从表1中获得表2&3中不存在的所有详细信息。我们可以两次使用NOT IN吗?

Answers:


310

要使用IN,您必须有一个set,请改用以下语法:

SELECT * FROM Table1 WHERE Table1.principal NOT IN (SELECT principal FROM table2)

85
小心的时候table2.principal可以NULL。在这种情况下,NOT IN将始终返回,FALSE因为NOT IN将其视为<> ALL,它将像这样比较子查询中的所有行,与进行比较Table1.principal <> table2.principal时失败NULLTable1.principal <> NULL将不会导致TRUE。解决方法:NOT IN (SELECT principal FROM table2 WHERE principal IS NOT NULL)
巴斯蒂2015年

4
感谢您的评论@Basti!花了很多时间试图理解为什么查询无法正常工作。
gvas

3
不要忘记避免在“ NOT IN”列表中使用“ SELECT *”。您必须选择一个特定的列。:否则,你会得到这个错误stackoverflow.com/questions/14046838/...
洛瑞恩布伦

165

subquery选项已经被回答,但是请注意,在许多情况下,a LEFT JOIN可以是一种更快的方法:

SELECT table1.*
FROM table1 LEFT JOIN table2 ON table2.principal=table1.principal
WHERE table2.principal IS NULL

如果要检查多个表以确保它不存在于任何表中(如SRKR的注释中所示),则可以使用以下方法:

SELECT table1.*
FROM table1
LEFT JOIN table2 ON table2.name=table1.name
LEFT JOIN table3 ON table3.name=table1.name
WHERE table2.name IS NULL AND table3.name IS NULL

2
在我自己的测试中,NOT IN&具有相同的性能LEFT JOIN。两者都+1
BufferStack

一旦查询运行一次,无论由于内部数据库缓存如何,您都应该获得相同的结果
Toote 2012年

对我来说,性能要好得多。当他们设置了外键时,我浏览了不同的表。
Keenora Fluffball 2013年

36

MySQL中的NOT IN与NOT EXISTS与LEFT JOIN / IS NULL

MySQL,以及除SQL Server之外的所有其他系统,都能够优化LEFT JOIN/IS NULLFALSE找到匹配值后立即返回,这是唯一记录此行为的系统。[…]由于MySQL无法使用HASHMERGE加入算法,因此ANTI JOIN它唯一能够使用的是NESTED LOOPS ANTI JOIN

[…]

本质上,[ NOT IN]LEFT JOIN/ IS NULL使用的计划完全相同,尽管这些计划是由不同的代码分支执行的,并且它们在结果中看起来也有所不同EXPLAIN。这些算法实际上是相同的,并且查询是同时完成的。

[…]

很难说出[使用NOT EXISTS] 时性能下降的确切原因,因为这种下降是线性的,并且似乎不依赖于数据分布,两个表中值的数量等,只要对两个字段都进行了索引。由于MySQL中有三段代码本质上只能完成一项工作,因此负责该代码的代码有可能EXISTS进行某种额外的检查,而这需要花费额外的时间。

[…]

MySQL可以优化所有三种方法来执行某种操作NESTED LOOPS ANTI JOIN。[…]但是,这三种方法生成三种不同的计划,这些计划由三种不同的代码执行。执行EXISTS谓词的代码的效率大约降低30%[…]

这就是为什么在MySQL中搜索缺失值最佳方法是使用LEFT JOIN/ IS NULLNOT IN而不是NOT EXISTS

(添加了重点)


7

不幸的是,这似乎与MySql的“ NOT IN”子句用法有关,下面的屏幕截图显示了返回错误结果的子查询选项:

mysql> show variables like '%version%';
+-------------------------+------------------------------+
| Variable_name           | Value                        |
+-------------------------+------------------------------+
| innodb_version          | 1.1.8                        |
| protocol_version        | 10                           |
| slave_type_conversions  |                              |
| version                 | 5.5.21                       |
| version_comment         | MySQL Community Server (GPL) |
| version_compile_machine | x86_64                       |
| version_compile_os      | Linux                        |
+-------------------------+------------------------------+
7 rows in set (0.07 sec)

mysql> select count(*) from TABLE_A where TABLE_A.Pkey not in (select distinct TABLE_B.Fkey from TABLE_B );
+----------+
| count(*) |
+----------+
|        0 |
+----------+
1 row in set (0.07 sec)

mysql> select count(*) from TABLE_A left join TABLE_B on TABLE_A.Pkey = TABLE_B.Fkey where TABLE_B.Pkey is null;
+----------+
| count(*) |
+----------+
|      139 |
+----------+
1 row in set (0.06 sec)

mysql> select count(*) from TABLE_A where NOT EXISTS (select * FROM TABLE_B WHERE TABLE_B.Fkey = TABLE_A.Pkey );
+----------+
| count(*) |
+----------+
|      139 |
+----------+
1 row in set (0.06 sec)

mysql> 

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.