1. 程式人生 > >SQL進價2:三值邏輯和null

SQL進價2:三值邏輯和null

not 比較 混亂 重要 括號 none query inf HERE

1、SQL中的bool類型的值有三種

普通編程語言裏的布爾型只有 truefalse 兩個值,這種邏輯體系被稱為二值邏輯。而 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 的情況:falseunknowntrue
  • OR 的情況:trueunknownfalse

優先級高的真值會決定計算結果。例如 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 謂詞永遠不會返回 unknownEXISTS 只會返回 true 或者 false。因此就有了 INEXISTS 可以互相替換使用,而 NOT INNOT 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