null是什麼?ide
不知道。我是說,他的意思就是不知道(unknown)。測試
它和true、false組成謂詞的三個邏輯值,表明「未知」。與true和false相比,null最難以使人捉摸,由於它沒有明確的值,在不一樣的場景下,它能表明不一樣的含義。下文以例子的方式給你們分享下null使用的典型場景及對應的用法。this
1.check約束與nullspa
以前在SQL ServerCentral.com上看到一個關於check約束的null問題,3d
做者建立了一個表,在字段orderstatus上設置了check約束,只能插入指定的value的行,如今插入幾行數據,其中有一行的value爲null,最後問最終有幾行能夠插入成功。code
原文以下:對象
I want to ensure that the status column for my Orders table only contains specific values. I decide to use this code:blog
create table Orders ( OrderID int primary key , OrderTotal MONEY , OrderStatus VARCHAR(20) constraint Orders_Status_Code check( OrderStatus in ('ACTIVE', 'INACTIVE', 'TBD')) ); go
Now I want to insert data into the table. I run this batch.教程
insert Orders select 1, 435.43, 'Active' insert Orders select 2, 554.66, 'InActive' insert Orders select 3, 129.12, 'Not Active' insert Orders select 4, 1228.00, NULL
How many rows are in the table? I am running on a default, SQL Server 2014 instance with US English defaults.ci
(你們先想一想答案,若是沒有把握就找個測試環境試一試)
《T-SQL基礎教程》中關於check約束與null的描述,著者用了一句言簡意賅的口訣「check約束拒絕false,接受true和null」。
在上面的例子中,當orderstatus爲‘Avative’和’InActive’時,check約束判斷的結果是true,因此會插入成功,當爲'Not Active’判斷的結果爲false,插入不成功,最後當爲'Null’時,判斷的結果是null,插入成功。
因此,正確答案是3。
null一個特殊性在於它沒法比較(和計算)。null與任何值的任何比較(和計算)都等於null。(unique約束除外,在unique約束中,null是相等的,同一個字段不容許出現兩次null)
好比判斷null=null的結果是null,判斷null<>null的結果也仍是null。下面我以不等於(<>)爲例,演示比較運算對null的判斷。
我先建立一個表,而後插入多行數據,其中有一行orderstatus的值爲null,
if object_id(N’Orders’) is not null drop table orders
create table Orders ( OrderID int primary key , OrderTotal MONEY , OrderStatus VARCHAR(20) ); go
insert Orders select 1, 435.43, 'Active' insert Orders select 2, 554.66, 'InActive' insert Orders select 3, 129.12, 'Not Active' insert Orders select 4, 1228.00, NULL
如今我執行了一個where orderstatus<>'Active' 的查詢,
select * from orders where OrderStatus<>'Active'
你們想一想null所在的行會不會在查詢結果裏面。
在上面的例子中,當orderstatus爲'InActive' 和'Not Active' 時,where條件判斷的結果爲true,但當orderstatus爲'null' 時,where OrderStatus<>'Active'等價於where null <>'Active',而null與任何一個值的比較結果仍是null,因此where條件判斷的結果爲null。
在SQL Server中,where篩選的原則是「接受true,拒絕false和null」(《T-SQL基礎教程》)。因此orderstatus爲'InActive' 和'Not Active'的行顯示在結果集總,而orderstatus爲null的行不會出如今結果集中。
最終,正確答案是:只會返回兩行
not in和not exists均可以用來判斷某個對象的存在與否,在大多數場景下二者能夠相互替換,但在遇到null時,由於前者是三值邏輯(true|false|unknow)判斷然後者只會返回true或false,所以處理的結果會有很大不一樣。
爲了演示二者的區別,咱們仍是沿用上文的表,分別使用not in和not exists執行一個查詢,找出OrderStatus 不爲'Active'和'InActive'的行。
if object_id(N’Orders’) is not null drop table orders
create table Orders ( OrderID int primary key , OrderTotal MONEY , OrderStatus VARCHAR(20) ); go
insert Orders select 1, 435.43, 'Active' insert Orders select 2, 554.66, 'InActive' insert Orders select 3, 129.12, 'Not Active' insert Orders select 4, 1228.00, NULL
在下面這個查詢中,where子句中使用not in來過濾數據,where子句的條件是OrderStatus not in ('Active','InActive'),咱們指望結果集中包含orderstatus爲'Not Active'、'NULL'這兩行的數據。
select * from orders where OrderStatus not in ('Active','InActive')
這個查詢中,當OrderStatus爲null時, 原where子句等價於where null <>'Active' AND null<>'InActive',這就變成了上文中介紹的比較運算與null的問題。where的判斷結果仍是null,因此該行不會出如今結果集中。而當OrderStatus爲'Not Active'時,知足where篩選的爲true的條件,會顯示在結果集中。
最終,正確答案是:只有一行。
說明:in與null的關係與此同理。
如今咱們仍是指望結果集中包含orderstatus爲'Not Active'、'NULL'這兩行的數據,此次用Not exists。
在這個查詢中,子查詢先求出OrderStatus='Active' or OrderStatus='InActive的行,而後外部查詢用not exists過濾子查詢的結果,將剩下的行顯示在最終結果集中。
SELECT * FROM orders AS o1 WHERE NOT EXISTS( SELECT * FROM orders AS o2 WHERE o1.OrderStatus = o2.OrderStatus AND ( o2.OrderStatus = 'Active' OR o2.OrderStatus = 'InActive' ));
爲了方便理解,咱們將子查詢改寫成自錶鏈接的方式,
select * from orders as o2 where o1.OrderStatus=o2.OrderStatus and (o2.OrderStatus='Active' or o2.OrderStatus='InActive' ))
改寫成:
SELECT * FROM orders AS o2 INNER JOIN orders o1 ON o1.OrderStatus = o2.OrderStatus AND ( o2.OrderStatus = 'Active' OR o2.OrderStatus = 'InActive' );
返回的結果集爲:
而後咱們再看外層查詢,
外部查詢指望使用not exists返回orders表中不包含子查詢結果集的行,也就是說,只要orders表沒有子查詢結果集中的行就返回true,不然返回false(只有存在和不存在,沒有unknown的說法)。
按照這個邏輯,orderID爲3和4的行不在子查詢的結果集中,所以not exists判斷爲true,而orderID爲1和2的行已包含在子查詢的結果集中,因此not exists判斷爲false。最後根據where篩選「接受true,拒絕false和null」的原則,最終只有orderID爲3和4的行顯示在結果集中。
說明:exists與null的關係與此同理。
not in其實是對一個對象的比較運算,而比較存在true|false|unknow三種邏輯值。
not exsits判斷某個對象存在或者不存在,它只有這兩種狀態,沒有unknown的說法。所以相比not in而言,not exists只會有true和false這兩種邏輯值。
總結:
上文介紹了null在不一樣場景中的含義,考慮到SQL不一樣的語言元素對null的不一樣處理方式,日常咱們在寫SQL語句的時候應該清晰思考本身編寫的每一個查詢對null或三值邏輯的處理,避免出現邏輯錯誤。