MySQL SELECT x FROM a WHERE NOT IN (SELECT x FROM b) - 意外结果

Posted

技术标签:

【中文标题】MySQL SELECT x FROM a WHERE NOT IN (SELECT x FROM b) - 意外结果【英文标题】:MySQL SELECT x FROM a WHERE NOT IN ( SELECT x FROM b ) - Unexpected result 【发布时间】:2010-11-03 07:44:02 【问题描述】:

我希望下面第三个查询的结果包含 id=732。它没有。这是为什么呢?

mysql> SELECT id FROM match ORDER BY id DESC LIMIT 5 ; +------------+ |编号 | +------------+ |第732章 | 730 | | 655 | |第458章 |第456章 +------------+ 5 行一组(0.00 秒) mysql> SELECT id FROM email ORDER BY id DESC LIMIT 5 ; +------------+ |编号 | +------------+ |第731章 |第727章 | 725 | |第724章 |第723章 +------------+ 5 行一组(0.00 秒) mysql> SELECT * FROM match WHERE id NOT IN (SELECT id FROM email); 空集(0.00 秒)

email.id 表中有 3 个 NULL 条目,match.id 中没有 NULL 条目。

完整的表/查询可以在http://pastebin.ca/1462094看到

【问题讨论】:

【参考方案1】:

来自documentation

为了符合SQL 标准,IN 不仅会在左侧的表达式为 NULL 时返回 NULL,而且如果在列表中未找到匹配项且在列表是NULL

这正是你的情况。

INNOT IN 都返回 NULL,这不是 WHERE 子句可接受的条件。

按如下方式重写您的查询:

SELECT  *
FROM    match m
WHERE   NOT EXISTS
        (
        SELECT  1
        FROM    email e
        WHERE   e.id = m.id
        )

【讨论】:

是OP的情况吗?我的理解是“如果没有找到匹配项并且列表中的表达式之一为 NULL”不是这种情况,因为应该找到 732,从而使该子句无效,对吧? @Eric:在电子邮件中找不到 732。【参考方案2】:

...或者如果你真的想使用NOT IN,你可以使用

SELECT * FROM match WHERE id NOT IN ( SELECT id FROM email WHERE id IS NOT NULL)

【讨论】:

这对我有用,想创建一个尚未选择的“仪表类型”下拉列表,即第二个表中没有记录 我更喜欢这个答案。不知道“where id is not null null”是使“不在”查询工作所必需的。【参考方案3】:

我对 MySQL 如何处理空值的细节有点脱节,但这里有两件事可以尝试:

SELECT * FROM match WHERE id NOT IN 
    ( SELECT id FROM email WHERE id IS NOT NULL) ;

SELECT
    m.*
FROM
    match m
    LEFT OUTER JOIN email e ON
        m.id = e.id
        AND e.id IS NOT NULL
WHERE
    e.id IS NULL

第二个查询看起来违反直觉,但它先是连接条件,然后是 where 条件。这就是连接和 where 子句不等价的情况。

【讨论】:

我的理解是使用左外连接对性能也更好。【参考方案4】:

下面是一些真正有意义的 SQL:

SELECT m.id FROM match m LEFT JOIN email e ON e.id = m.id WHERE e.id IS NULL

简单总是更好。

【讨论】:

虽然不直观,但实际上是最有效的解决方案。

以上是关于MySQL SELECT x FROM a WHERE NOT IN (SELECT x FROM b) - 意外结果的主要内容,如果未能解决你的问题,请参考以下文章

MySQL常用语句

06-mysql基础-mysql中的DQL-子查询

MySQL数据表查询操作

MySQL数据表查询操作

MySQL数据表查询操作

oracle 查看删除重复数据