SQL Server 查詢時NULL值問題

問題:

有一個表

col1     col2

---------------------

a           aa

b           NULL

c          cc

 

想要查詢這樣的一個結果:

col1     col2

---------------------

b           NULL

c          cc

 

查詢語句如下:

Select * From tb where col1<>'aa'

但是真實結果確是:

col1     col2

---------------------

c          cc

 

少了爲NULL的那條記錄,問題就出在WHERE後條件那裏。

改成:

Select * From tb where isnull(col1,'')<>'aa'

結果正確。

 

在網上找了一些關於NULL的資料,轉貼一下:

我們在 sql server 中用 DECLARE 申明一個變量時, sql server 將會把變量存儲在SQLs 內存空間的變量列表區域(variable table),變量列表中包含了變量的名稱和存儲地址。然而如果我們在創建變量的時候並沒有給變量賦值的話,sql server是沒有爲變量分配內存的,因此變量並沒有在內存中被定義。

然後當你用 SET 關鍵字給變量賦值的話,sql server 將爲這個值分配內存空間並將地址存放在變量列表(variable table)中。如果你再次爲這個變量賦值的話新的內存地址將替換舊的地址。

       下面我們就來討論一下 “= NULL”和“IS NULL”的區別。

“= NULL”

    = NULL”是值表達式。意味着,這個表達式會判斷是否已經爲變量正確設置了值。事實上我們是可以設置一個變量的值爲 NULL 的(如果設置變量 = NULL,這就說明變量的值是未知的 unknown)。參考下面的代碼。

DECLARE @val CHAR(4)

SET @val = NULL

    我們顯式給變量賦值 NULLsql server會爲變量分配內存空間並指出變量值是未知的 unknown,因此下面的表達式將返回true(因爲我們已經通過 SET @val = NULL 爲變量分配了內存空間):

If @val = NULL

    但如果我們像下面的代碼段一樣在申明變量的時候不給變量賦值:

DECLARE @val CHAR(4)

If @val = NULL

   表達式將返回 false  

    導致這種情況的原因是,在沒有給變量賦值的情況下,sql server 是不會爲變量分配內存空間,因此地址是未知的就無法進行值的比較了。

Note: 上面的示例結果與 ANSI_NULLS (ON|OFF) 的設置有關。

“IS NULL”

    “IS NULL”的情況就有點微妙,在需要比較變量值是不是爲 NULL 的時候它應該是首選的用法。IS NULL 會同時檢查變量地址和變量的地址所指向的值是不是未知的(unknown)。

研究一下下面的代碼:

  • DECLARE @val CHAR(4)
  • If @val IS NULL
  •             PRINT 'TRUE'
  • ELSE
  •             PRINT 'FALSE'

  • SET @val = NULL
  • If @val IS NULL
  •             PRINT 'TRUE'
  • ELSE
  •             PRINT 'FALSE'

上面兩個表達式都會返回 TRUE, 原因是 IS NULL 同時比較地址和值是不是未知的。


 

ANSI_NULLS

SET ANSI_NULLS (ON|OFF)

     環境變量 SET ANSI_NULLS (ON|OFF) 的設置對 “= NULL”的表達式會有很大的影響,下面的段落摘錄自sql server 的幫助,它很好的解釋了這一因素。(SET ANSI_NULLS 詳細的說明參考sql server 幫助)

SQL-92 標準要求對空值的等於 (=) 或不等於 (<>) 比較取值爲 FALSE。當 SET ANSI_NULLS  ON 時,即使 column_name 中存在空值,使用 WHERE column_name = NULL  SELECT 語句仍返回零行。即使 column_name 中存在非空值,使用 WHERE column_name <> NULL  SELECT 語句仍返回零行。

 SET ANSI_NULLS  OFF 時,等於 (=) 和不等於 (<>) 比較運算符不遵從 SQL-92 標準。使用 WHERE column_name = NULL  SELECT 語句返回 column_name 中含有空值的行。使用 WHERE column_name <> NULL  SELECT 語句返回列中含有非空值的行。此外,使用 WHERE column_name <> XYZ_value  SELECT 語句返回所有非 XYZ 值和非 NULL的行。

 SET ANSI_NULLS  ON 時,所有對空值的比較均取值爲 UNKNOWN。當 SET ANSI_NULLS  OFF 時,如果數據值是 NULL,則所有數據對空值的比較將取值爲 TRUE。如果未指定,則應用當前數據庫的 ANSI nulls 選項的設置。

爲使腳本按預期運行,不管 ANSI nulls 數據庫選項或 SET ANSI_NULLS 的設置是什麼,在可能包含空值的比較中使用 IS NULL  IS NOT NULL

所以我們在需要判斷NULL的時候最好使用 IS NULL 和 IS NOT NULL。儘量避免使用 = NULL 和 <> NULL, 因爲後者會產生非預期的效果。    

在 SET ANSI_NULLS 設置不同時下面的 sql 語句會產生不同結果:

SELECT * FROM t1 WHERE a = NULL

SELECT * FROM t1 WHERE a <> NULL

SELECT * FROM t1 WHERE a IS NULL

 

 

 

發佈了15 篇原創文章 · 獲贊 2 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章