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
。
这正是你的情况。
IN
和 NOT 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) - 意外结果的主要内容,如果未能解决你的问题,请参考以下文章