MySQL"NOT IN"查询

Ksh*_*KJ- 175 mysql sql

我想运行一个简单的查询来抛出Table1另一个表(Table2)中的列中不存在主列值的所有行.

我试过用:

SELECT * FROM Table1 WHERE Table1.principal NOT IN Table2.principal
Run Code Online (Sandbox Code Playgroud)

这反而引发语法错误.谷歌搜索引领我去论坛,人们都说MySQL不支持NOT IN,需要使用极其复杂的东西.这是真的?或者我犯了一个可怕的错误?

Jul*_*ain 302

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

SELECT * FROM Table1 WHERE Table1.principal NOT IN (SELECT principal FROM table2)
Run Code Online (Sandbox Code Playgroud)

  • 当`table2.principal`可以是'NULL`时要小心.在这种情况下,`NOT IN`将始终返回`FALSE`,因为`NOT IN`被视为`<> ALL`,它比较子查询中的所有行,如`Table1.principal <> table2.principal`,这在比较时失败使用`NULL`:`Table1.principal <> NULL`不会导致`TRUE`.修复:`NOT IN(SELECT principal FROM table2 WHERE principal IS NOT NULL)`. (77认同)
  • 感谢@Basti的评论!花了很多时间试图理解为什么查询没有按预期工作. (3认同)
  • 不要忘记避免在'NOT IN'列表中使用'SELECT*'.您必须选择特定列.否则你会收到这个错误:/sf/ask/983278691/ (3认同)

Luk*_*ský 164

子查询选项已经得到解答,但请注意,在许多情况下,LEFT JOIN可以采用更快的方式执行此操作:

SELECT table1.*
FROM table1 LEFT JOIN table2 ON table2.principal=table1.principal
WHERE table2.principal IS NULL
Run Code Online (Sandbox Code Playgroud)

如果要检查多个表以确保它不存在于任何表中(例如在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
Run Code Online (Sandbox Code Playgroud)

  • 在我自己的测试中,"NOT IN"和"LEFT JOIN"的表现相同.+1两者 (2认同)

eng*_*gin 36

在MySQL中,NOT IN与NOT EXISTS与LEFT JOIN/IS为空

MySQL以及除SQL Server之外的所有其他系统能够在找到匹配值后立即优化LEFT JOIN/IS NULL返回FALSE,并且它是唯一一个关注此行为的系统.[...]由于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.

(重点补充)


Leg*_*gna 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> 
Run Code Online (Sandbox Code Playgroud)


小智 5

小心NOT IN不是别名<> ANY,但是<> ALL!

http://dev.mysql.com/doc/refman/5.0/en/any-in-some-subqueries.html

SELECT c FROM t1 LEFT JOIN t2 USING (c) WHERE t2.c IS NULL
Run Code Online (Sandbox Code Playgroud)

不能被替换

SELECT c FROM t1 WHERE c NOT IN (SELECT c FROM t2)
Run Code Online (Sandbox Code Playgroud)

你必须使用

SELECT c FROM t1 WHERE c <> ANY (SELECT c FROM t2)
Run Code Online (Sandbox Code Playgroud)