2011-08-31 160 views
1

鉴于当CASE语句也意外的行为:SQL服务器:比较NULL

下面的SELECT语句:

select case NULL 
     when NULL then 0 
     else 1 
     end 

问题:

我期待这个返回0而是它返回1.什么给了?

回答

9

一般来说,NULL不是你应该试图比较的相等性,这是case语句所做的。你可以使用“Is NULL”来测试它。没有期望NULL != NULLNULL = NULL。这是一个不确定的,未定义的值,而不是一个硬性常数。

- 涵盖在评论的问题 -

如果您需要检索时可能遇到的一个NULL列中的值,试试这个来代替:

Case 
    When SomeColumn IS NULL 
    Then 0 
    Else 1 
End 

我认为,应该工作。就你原来的帖子而言:

Select Case NULL 
    When NULL then 0 // Checks for NULL = NULL 
    else 1 // NULL = NULL is not true (technically, undefined), else happens 
end 

问题在于你的Case选择会自动尝试使用相等操作。这根本不适用于NULL。

+0

@Martin - 没错。你不应该使用NULL的比较运算符。 'IS NULL'是正确的方法。我的'NULL!= NULL'是试图比较两个可能包含NULL值的列的引用。即使它们都是NULL,它们也不相等。 –

+1

@Martin - 对不起,当我重读它时,我收集了你正在解释的内容。你是对的,两个比较运算符都不对NULL。我试着清理一下答案。 –

+0

好的,那么让我问你:当我比较一个空值的列正在做同样的事情时,我遇到了这个问题。那么,为什么'选择case SomeColumn当NULL然后0 else 1 end'或者你是说问题在于when子句而不是select case? – DJTripleThreat

0

您需要使用IS NULL运算符。标准比较运算符不适用于NULL。

3

除了其他的答案,你需要稍微改变一下语法CASE到这样做:

SELECT CASE 
    WHEN NULL IS NULL THEN 0 
    ELSE 1 
    END; 

在您的语法中使用该值隐式使用等于比较。 NULL是未知的,所以是NULL = NULL,所以用你现在的代码,你将永远得到 1(geez我也是)。

要获得您想要的行为,您可以使用SET ANSI_NULLS ON;但请注意,这可能会以您无法预测的方式更改其他代码,并且该设置已弃用 - 因此它将在SQL Server的未来版本中完全停止工作(请参阅this SQL Server 2008 doc)。

3

我打算在Aaron的答案中加入这个评论,但是它太长了,所以我会把它作为另一个答案的一部分加入。

CASE statement实际上有两种不同的模式,简单和搜索。

从BOL:

的情况下表达有两种格式:

  • 简单情况下表达的表达与一组简单的表达式来确定结果。

  • CASE搜索表达式计算一组布尔表达式以确定结果。

当简单CASE(你的例子)做什么它描述为比较它的相等比较 - 即=

这就是后来的文件中明确:

简单情况下表达被第一表达 比较操作在每个WHEN子句中用于等价的表达式。如果这些 表达式是等价的,则THEN子句中的表达式将返回 。

  • 只允许相等性检查。

因为anything = NULL是ANSI SQL总是假的(如果你不知道这没有,你需要更多的一般在SQL的NULL读了,尤其还与其他行为的搜索比较 - WHERE x IN (a, b, c) ),你不能在简单的情况下,无论是在最初的表达或表达的列表,针对被比较使用NULL,并它曾经被比作一个值,具有NULL

如果你想检查NULL,你将不得不使用IF/ELSE结构或搜索CASE一个完整的表达式。

我同意,这是种不幸没有版本支持的还是比较更容易写:

select case colname 
    when IS NULL then 0 
    else 1 
end 

这将使编写更容易某些长CASE声明:

select case colname 
    when IS NULL then '' 
    when 1 then 'a' 
    when 2 then 'b' 
    when 3 then 'c' 
    when 4 then 'd' 
    else 'z' 
end 

但这只是一厢情愿的想法...

一个选项是使用ISNULLCOALESCE

select case COALESCE(colname, 999999) -- 999999 is some value never used 
    when 999999 then '' 
    when 1 then 'a' 
    when 2 then 'b' 
    when 3 then 'c' 
    when 4 then 'd' 
    else 'z' 
end 

但它并不总是一个很好的选择。

+0

+1真棒帖子,凯德。 – DJTripleThreat