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