我使用以下查询:
select count(*) from Table1 where CurrentDateTime>'2012-05-28 15:34:02.403504' and Error not in ('Timeout','Connection Error');
令人惊讶的是,此语句不包含具有错误值为NULL的行。我的意图是仅过滤具有错误值的行作为'超时' (或)'连接错误'。我需要提供一个附加条件(OR Error为NULL)来检索正确的结果。
为什么MYSQL使用NULL值过滤结果? 我认为IN关键字会返回一个布尔结果(1/0),现在我明白一些MYSQL关键字不会返回布尔值,它也可能返回NULL ....但为什么将NULL视为特殊?
答案 0 :(得分:23)
这:
Error not in ('Timeout','Connection Error');
在语义上等同于:
Error <> 'TimeOut' AND Error <> 'Connection Error'
关于空比较的规则也适用于IN。因此,如果Error的值为NULL,则数据库无法使表达式成为真。
要修复,你可以这样做:
COALESCE(Error,'') not in ('Timeout','Connection Error');
或者更好:
Error IS NULL OR Error not in ('Timeout','Connection Error');
或者更好的是:
CASE WHEN Error IS NULL THEN 1
ELSE Error not in ('Timeout','Connection Error') THEN 1
END = 1
OR
不会短路,CASE会以某种方式使您的查询短路
也许一个具体的例子可以说明NULL NOT IN expression
为什么不返回任何内容:
鉴于此数据:http://www.sqlfiddle.com/#!2/0d5da/11
create table tbl
(
msg varchar(100) null,
description varchar(100) not null
);
insert into tbl values
('hi', 'greet'),
(null, 'nothing');
你做这个表达:
select 'hulk' as x, msg, description
from tbl where msg not in ('bruce','banner');
只会输出'hi'。
NOT IN翻译为:
select 'hulk' as x, msg, description
from tbl where msg <> 'bruce' and msg <> 'banner';
NULL <> 'bruce'
无法确定,甚至不是真的,甚至不是假的
NULL <> 'banner'
无法确定,甚至不是真的
所以null值表达式,有效地解析为:
can't be determined AND can't bedetermined
事实上,如果您的RDBMS支持SELECT上的布尔值(例如MySQL,Postgresql),您可以看到原因:http://www.sqlfiddle.com/#!2/d41d8/828
select null <> 'Bruce'
返回null。
这也返回null:
select null <> 'Bruce' and null <> 'Banner'
鉴于您使用的是NOT IN
,它基本上是一个AND表达式。
NULL AND NULL
结果为NULL。所以就像你在做:http://www.sqlfiddle.com/#!2/0d5da/12
select * from tbl where null
不会返回任何内容
答案 1 :(得分:1)
因为null未定义,所以null不等于null。您始终必须显式处理null。
答案 2 :(得分:1)
IN
,则 NULL
会返回NULL
。要获得NULL
值,您必须执行以下操作:
select count(*) from Table1 where CurrentDateTime>'2012-05-28 15:34:02.403504' and (Error not in ('Timeout','Connection Error') or Error is null);
答案 3 :(得分:1)
IN
返回一个三价BOOLEAN
(接受NULL
作为值)。 NOT IN
返回IN
的三价否定,NULL
的否定为NULL
。
想象一下,我们在1
中有一个包含1,000,000
到id
的所有数字的表格以及此查询:
SELECT *
FROM mytable
WHERE id IN (1, 2, NULL)
或等同物:
SELECT *
FROM mytable
WHERE id = ANY
(
SELECT 1
UNION ALL
SELECT 2
UNION ALL
SELECT NULL
)
对于TRUE
,谓词返回1
,对于所有其他值,谓词返回2
和NULL
,因此会返回1
和2
。< / p>
在它的对立面:
SELECT *
FROM mytable
WHERE id NOT IN (1, 2, NULL)
,或
SELECT *
FROM mytable
WHERE id <> ALL
(
SELECT 1
UNION ALL
SELECT 2
UNION ALL
SELECT NULL
)
,对于所有其他值,谓词返回FALSE
1
和2
以及NULL
,因此不返回任何内容。
请注意,布尔否定不仅会将运算符(=
更改为<>
),还会将量词(ANY
更改为ALL
)。
答案 4 :(得分:0)
错误不在('超时','连接错误');
在语义上等同于:
错误&lt;&gt; 'TimeOut'和错误&lt;&gt; '连接错误'
关于空比较的规则也适用于IN。因此,如果Error的值为NULL,则数据库无法使表达式为true。
在[1]中,我发现这句话证实了他最重要的陈述,用于理解为什么IN失败为NULL。在[1]中的规范(“specs”)中,您将:“如果一个或两个参数为NULL,则比较结果为NULL,但NULL安全&lt; =&gt;相等比较运算符除外。” p>
所以是的,遗憾的是Mysql在这种情况下迷失了。我认为Mysql设计者不应该这样做,因为当我将2与NULL进行比较时,Mysql应该能够看到它们是不同的,而不是简单地抛出错误的结果。例如,我做了:
select id from TABLE where id not in (COLUMN WITH NULLS);
然后它会抛出EMPTY结果。但。如果我做
select id from TABLE where id not in (COLUMN WITH OUT NULLS);
它显示了正确的结果。因此,在使用IN运算符时,必须过滤掉NULLS。作为用户,这不是我想要的行为,但它在[1]的规范中有记载。我认为语言和技术应该更简单,因为你应该能够在不需要阅读规范的情况下进行DEDUCE。确实,2与NULL不同,我应该是负责控制和处理更高抽象级别错误的人,但MySQL在将NULL与特定值进行比较时应该抛出一个FALSE结果。
规格参考:[1] http://dev.mysql.com/doc/refman/5.6/en/type-conversion.html
答案 5 :(得分:0)
很抱歉在同一个论坛上发帖两次,但我想说明另一个例子:
我同意@Wagner Bianchi在[2]的论坛中说: &LT;&LT;处理数据和子查询&gt;&gt;
时,这是非常巧妙的此外,这不应该是行为,我认为Mysql的设计师在[1]中记录这个决定时会犯错误。设计应该是不同的。让我解释一下:比较时你知道吗
select (2) not in (1, 4, 3);
you will get:
+----------------------+
| (2) not in (1, 4, 3) |
+----------------------+
| 1 |
+----------------------+
1 row in set (0.00 sec)
但是如果在列表中你至少有一个NULL,那么:
select (2) not in (1, NULL, 3);
throws:
+-------------------------+
| (2) not in (1, NULL, 3) |
+-------------------------+
| NULL |
+-------------------------+
1 row in set (0.00 sec)
This is pretty absurd.
我们不是第一个对此感到困惑的人。见[2]
参考文献:
[1] http://dev.mysql.com/doc/refman/5.0/en/comparison-operators.html#function_in
[2] http://blog.9minutesnooze.com/sql-not-in-subquery-null/comment-page-1/#comment-86954