2010-03-25 27 views
2

请考虑以下Transact sql。奇怪的SQL行为,我想知道为什么它的工作方式如此

DECLARE @table TABLE(val VARCHAR(255) NULL) 

INSERT INTO @table (val) VALUES('a') 
INSERT INTO @table (val) VALUES('b') 
INSERT INTO @table (val) VALUES('c') 
INSERT INTO @table (val) VALUES('d') 
INSERT INTO @table (val) VALUES(NULL) 

select val 
from @table 
where val not in ('a') 

我希望它可以返回

b, c, d, NULL 

,而是它返回

b, c, d 

为什么会出现这种情况? NULL没有被评估?某种程度上在设置'a'中是否为NULL?

+1

我相信,如果你改变你的Where-Clause,你仍然可以选择那些NULL。像这样:'WHERE VAL NOT IN('a')OR VAL IS NULL'。但是,NULL肯定不会被设置为'a'。 – 2010-03-25 20:34:24

+0

我最近遇到了类似的问题。在被这种行为烧毁之前,您可以使用SQL多长时间令人惊叹。 – harpo 2010-03-25 20:37:23

+0

PS。我经常说'我*******恨空!' – CResults 2010-03-25 20:41:01

回答

3

答案

默认情况下,对于SQL而言,NULL表示“未知”。所以,与“未知”的任何比较都是“未知”。

例如,如果一个陌生人站在鲍勃旁边,并且想问一个问题:“陌生人的名字是否与鲍勃的名字相同?”。答案是未知的。

由于您要求“返回值不是'A'的任何记录”。当它到达NULL列时,SQL仍会说“我不知道”。由于该表达式不计算为真,该记录不会被返回。

,其比较NULL到恒定永远是NULL,所以使用特殊IS NULLIS NOT NULL测试对于NULL值的任何表达式。

这将让你bcdNULL

SELECT val 
FROM @table 
WHERE val NOT IN ('a') OR val IS NULL 

的解决方法

您可以更改为空值的默认行为:

SET ANSI_NULLS OFF 
+0

谢谢你对陌生人的评论。我总是将null视为未设置。所以如果我问的是,陌生人的名字与鲍勃的名字相同,答案将是否定的,因为陌生人没有名字。这显然与集合论所表达的不一样。 – 2010-03-25 21:06:27

+0

关于解决方法的一个警告:如果您依赖于此行为,并且您的代码在“野外”(无法控制ANSI_NULLS设置)运行,则可能看似随机错误。在这种情况下*更好地测试。 – DaveE 2010-03-25 22:50:40

+0

@DaveE,我同意。我不推荐解决方法。解决方案更好。 – 2010-03-26 04:05:39

3

得到空行的尝试:

select val 
from @table 
where val not in ('a') OR val IS NULL 

尝试这些:

select 1 where null in (null) 
select 1 where null in (1) 
select 1 where 1 in (null) 

都返回零行

空= NULL永远是假的空= anythng IS总是为假,当测试NULL行时,WHERE子句是('a')中的WHERE NULL,所以它总是假的。

+0

我明白,但我想知道为什么我必须声明,NULL不在集合'a',所以我期望该行返回。 – 2010-03-25 20:34:00

+2

Null未定义,不能确定它是否在一个集合中,因为它不能与任何东西进行比较。除非您按照Quesi的建议更改SQL Server处理空值的方式。否则,你必须检查一个值是否未定义(即为空)。 – Mayo 2010-03-25 20:37:46

+1

Matthew,NULL *从来没有和任何东西*进行比较,甚至不是自己。因此,您必须使用[NOT] IS NULL明确地测试它。不包含空值,因为它不能被包含在“('a')”中。 – DaveE 2010-03-25 20:37:56

2

空不能直接比较任何东西。

尝试

select val 
from @table 
where coalesce(val, '') not in ('a') 
2

试试这个,你会得到不同的答案:

set ansi_nulls off; 
DECLARE @table TABLE(val VARCHAR(255) NULL) 

INSERT INTO @table (val) VALUES('a') 
INSERT INTO @table (val) VALUES('b') 
INSERT INTO @table (val) VALUES('c') 
INSERT INTO @table (val) VALUES('d') 
INSERT INTO @table (val) VALUES(NULL) 

select val 
from @table 
where val not in ('a') 

您有ANSI_NULLS,所以它相应的处理空值。

+0

欲了解更多信息,谷歌“数学集操作”,并开始阅读设置逻辑。设置逻辑对于使用RDMS来说是很好的背景知识。 – 2010-03-25 20:36:10

2

用这种方法你不能与NULL做相等。

考虑这个

select case when 'a' = NULL then 1 else 0 end 
select case when 'a' <> NULL then 1 else 0 end 

对于上面你会得到

result 
------ 
    0 
    0 

您所查询的尝试

where isnull(val,'') not in ('a') 
相关问题