为什么MYSQL IN关键字不考虑NULL值

Viv*_*k S 9 mysql mysql-python

我使用以下查询:

select count(*) from Table1 where CurrentDateTime>'2012-05-28 15:34:02.403504' and Error not in ('Timeout','Connection Error');
Run Code Online (Sandbox Code Playgroud)

令人惊讶的是,此语句不包含具有错误值为NULL的行.我的意图是仅将具有错误值的行过滤为"超时"(或)"连接错误".我需要提供一个附加条件(OR错误为NULL)来检索正确的结果.

为什么MYSQL使用NULL值过滤掉结果?我认为IN关键字将返回一个布尔结果(1/0),现在我明白一些MYSQL关键字不返回布尔值,它也可能返回NULL ....但为什么它将NULL视为特殊?

Mic*_*uen 25

这个 :

Error not in ('Timeout','Connection Error');
Run Code Online (Sandbox Code Playgroud)

在语义上等同于:

Error <> 'TimeOut' AND Error <> 'Connection Error'
Run Code Online (Sandbox Code Playgroud)

关于空比较的规则也适用于IN.因此,如果Error的值为NULL,则数据库无法使表达式为true.

要修复,你可以这样做:

COALESCE(Error,'') not in ('Timeout','Connection Error');
Run Code Online (Sandbox Code Playgroud)

或者更好的是:

Error IS NULL OR Error not in ('Timeout','Connection Error');
Run Code Online (Sandbox Code Playgroud)

或者更好的是:

 CASE WHEN Error IS NULL THEN 1
 ELSE Error not in ('Timeout','Connection Error') THEN 1
 END = 1
Run Code Online (Sandbox Code Playgroud)

OR 没有短路,CASE可以某种方式使您的查询短路


也许一个具体的例子可以说明为什么不NULL NOT IN expression返回:

鉴于此数据:http://www.sqlfiddle.com/#!2/dd5da/11

create table tbl
(
  msg varchar(100) null,
  description varchar(100) not null
  );


insert into tbl values
('hi', 'greet'),
(null, 'nothing');
Run Code Online (Sandbox Code Playgroud)

你做这个表达:

select 'hulk' as x, msg, description 
from tbl where msg not in ('bruce','banner');
Run Code Online (Sandbox Code Playgroud)

那只会输出'hi'.

NOT IN翻译为:

select 'hulk' as x, msg, description 
from tbl where msg <> 'bruce' and msg <> 'banner';
Run Code Online (Sandbox Code Playgroud)

NULL <> 'bruce' 不能确定,甚至不是真的,甚至不是假的

NULL <> 'banner' 无法确定,甚至不是真的甚至是假的

所以null值表达式,有效地解决了:

can't be determined AND can't bedetermined
Run Code Online (Sandbox Code Playgroud)

事实上,如果您的RDBMS支持SELECT上的布尔值(例如MySQL,Postgresql),您可以看到原因:http://www.sqlfiddle.com/#!2/d41d8/828

select null <> 'Bruce' 
Run Code Online (Sandbox Code Playgroud)

返回null.

这也返回null:

select null <> 'Bruce' and null <> 'Banner'
Run Code Online (Sandbox Code Playgroud)

鉴于您正在使用NOT IN,这基本上是一个AND表达式.

NULL AND NULL
Run Code Online (Sandbox Code Playgroud)

结果为NULL.所以这就像你在做:http://www.sqlfiddle.com/#!2/dd5da/12

select * from tbl where null
Run Code Online (Sandbox Code Playgroud)

什么都不会退还