SQL進價2:三值邏輯和null
1、SQL中的bool類型的值有三種
普通編程語言裏的布爾型只有 true
和 false
兩個值,這種邏輯體系被稱為二值邏輯。而 SQL 語言裏,除此之外還有第三個值 unknown
,因此這種邏輯體系被稱為三值邏輯(three-valued logic)。
2、null不是值,與數學運算符結果的結果永遠是unknown
常聽到的“列的值為 NULL
” 、“NULL
值”這樣的說法本身就是錯誤的。因為 NULL
不是值,NULL
不是值NULL
不是值!(如果有人認為 NULL
是值,那麽它是什麽類型的值?關系數據庫中存在的值必然屬於某種類型,比如字符型或數值型等。所以,假如 NULL
是值,那麽它就必須屬於某種類型。)
另外,註意:要想和null比較只能用 is null 或者 is not null,這樣才會返回true或者false。另外永遠記住一點,null和<,<,=,<>這些放在一起結果永遠是unknown,如 2=null,結果肯定是unknown,而unknown可在三值邏輯中不是true或者false,在寫where子句的篩選條件時尤其要註意。舉例來講:
接下來我們總結一下 SQL 遵循的三值邏輯的真值規律(理解下面這些非常重要)。
先看下圖:(t:true,f:false,u:unknown。not unknown 的結果是 unknown)
我們經常會遇到判斷篩選條件的結果(為true/false/unknown的一種,且SQL只會取返回結果是true的記錄),它們通常是and 或or連接這些單個條件的,如:where age>18 and sex=0或where age<18 and sex =unknown。所以我們要牢牢記住上面這個圖
記憶方式1:
and運算,只要有一邊是unknown,另一邊是false,那結果就是false,其它情況下,只要任意一邊有unknown,結果就是unknown。
or運算,只要一邊是unknown,那麽結果永遠就是unknown
記憶方式2:
在判斷and或or的最終結果時,請註意true/false/unknown之間有下面這樣的優先級順序。
AND
的情況:false
>unknown
>true
OR
的情況:true
>unknown
>false
優先級高的真值會決定計算結果。例如 true AND unknown
,因為 unknown
的優先級更高,所以結果是 unknown
true OR unknown
的話,因為 true
優先級更高,所以結果是 true
。記住這個順序後就能更方便地進行三值邏輯運算了。特別需要記住的是,當 AND
運算中包含 unknown
時,結果肯定不會是 true
(反之,如果 AND
運算結果為 true
,則參與運算的雙方必須都為 true
)。這一點對理解後文非常關鍵。
3、NOT IN 和 NOT EXISTS 不是等價的
如果 NOT IN
子查詢中用到的表裏被選擇的列中存在 NULL
,則 SQL 語句整體的查詢結果永遠是空。EXISTS
謂詞永遠不會返回 unknown
。EXISTS
只會返回 true
或者 false
。因此就有了 IN
和 EXISTS
可以互相替換使用,而 NOT IN
和 NOT EXISTS
卻不可以互相替換的混亂現象。
4、ALL
運算符與null
以下是ALL
運算符語法:
scalar_expression comparison_operator ALL ( subquery )
在上面語法中,
scalar_expression
是任何有效的表達式。comparison_operator
是任何有效的比較運算符,包括等於(=
),不等於(<>
),大於(>
),大於或等於(>=
),小於(<
),小於或等於(<=
)。- 括號內的子查詢(
subquery
)是一個SELECT語句,它返回單個列的結果。 此外,返回列的數據類型必須與標量表達式的數據類型相同。
如果所有比較對(scalar_expression,v)
的計算結果為TRUE
,則ALL
運算符返回TRUE
; v
是單列結果中的值。
如果其中一對(scalar_expression,v)
返回FALSE
,則ALL
運算符返回FALSE
。
如果all裏面的子查詢返回的單列中有null的存在,那麽這個all表達式就永遠不會篩選出任何數據,結果肯定為空。
因為ALL
謂詞其實是多個以 AND
連接的邏輯表達式的省略寫法。
如果all裏面的子查詢返回的單列中有null的存在,比如子查詢結果如下面這個情況,那麽具體的分析步驟如下所示。
--1. 執行子查詢獲取年齡列表
SELECT *
FROM Class_A
WHERE age < ALL ( 22, 23, NULL );
--2. 將ALL 謂詞等價改寫為AND
SELECT *
FROM Class_A
WHERE (age < 22) AND (age < 23) AND (age < NULL);
--3. 對NULL 使用“<”後,結果變為 unknown
SELECT *
FROM Class_A
WHERE (age < 22) AND (age < 23) AND unknown;
--4. 如果AND 運算裏包含unknown,則結果不為true
SELECT *
FROM Class_A
WHERE false 或 unknown;
--5.查詢結果為空
SQL進價2:三值邏輯和null