問題:
有一個表
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
我們顯式給變量賦值 NULL,sql 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