SQL 查詢中的 NULL 值

駭客與畫家發表於2020-04-05

SQL 查詢中的 NULL 值

本文通過各種 SQL 小例子,解釋 NULL 值的用途和帶來的問題。

英語原文地址:mitchum.blog/null-values…

作者:MITCHUM

翻譯:高行行

參考翻譯文章:blog.csdn.net/lnotime/art…

小結:

  • SQL 裡的 NULL 和其他程式語言裡的 NULL 是完全不同的東西
  • 在 SQL 中 NULL 為未知

翻譯水平有限,可能存在翻譯不準確的地方,盡情諒解。

今天的帖子是關於 SQL 中的 NULL 值的,由我的朋友兼資料庫嚮導 Kaley 提供。如果你想了解有關 SQL,Oracle 資料庫以及使查詢執行更快的更多資訊,請訪問他的網站


這是一個使很多萌新開發人員陷入困境的話題-SQL 查詢中 NULL 值的概念。

每當你向資料庫發出SQL查詢時……你想知道一列中是否包含 NULL 值……編寫查詢以查到結果的正確方式是什麼?

你應該使用這樣的查詢嗎?

SELECT * FROM SOME_TABLE
WHERE SOME_COLUMN = NULL
複製程式碼

要麼!你應該使用這樣的查詢嗎?

SELECT * FROM SOME_TABLE
WHERE SOME_COLUMN IS NULL
複製程式碼

…答案是,你應該使用第二個查詢(SOME_COLUMN IS NULL)。

下圖為實際的查詢例子 ?

SQL 查詢中的 NULL 值

SQL 查詢中的 NULL 值

SQL 查詢中的 NULL 值

為什麼呢?

為什麼其他的比較都不用 IS 關鍵字呢?

如果我們想知道一個欄位是否等於 1,我們可以使用如下的 WHERE 子句:

WHERE SOME_COLUMN = 1
複製程式碼

那麼為什麼我們在IS關鍵字上使用 NULL 值呢?為什麼我們需要區別對待 NULL ?

答案是這樣的:在 SQL 中,NULL 表示“未知”的概念 _ _(因此 NULL 值表示“未知”值)。

1. Null 為未知

在大多數資料庫中,NULL 和空字串(由雙撇號 "" 或 '' 表示)之間存在差異。

但是,並非所有資料庫都這樣:例如,Oracle 資料庫不允許你使用空字串。任何時候 Oracle 資料庫看到一個空字串,它都會自動將空字串轉換為 NULL 值。

但是,對於大多數其他資料庫,NULL 值與空字串的處理方式不同:

  • 空字串被視為沒有值的已知值**。**
  • 將 NULL 值視為未知值

舉個例子,就好像問:美國總統西奧多·羅斯福的中間名是什麼?

  • 一種答案可能是:“嗯,我不知道西奧多·羅斯福的中間名是什麼。”(此想法可以由 Theodore Roosevelt 的記錄的 MIDDLE_NAME 列中的 NULL 值表示,即中間名欄位為 NULL)
  • 另一種答案可能是**“西奧多·羅斯福總統實際上沒有中間名。他的父母從未給他起過中間名,我知道的事實就是西奧多·羅斯福(Theodore Roosevelt)沒有中間名。 **(你可以通過在 MIDDLE_NAME 列中輸入一個空字串或 '' 來表示,即中間名欄位為空字串)

Oracle 資料庫是最顯著的例外,其中這兩個值實際上都將由 NULL 表示-除 Oracle 以外的大多數資料庫對 NULL 和空字串的處理方式都非常不同。

只要你記得 NULL 值代表一個未知值,那麼這將有助於你編寫 SQL 查詢,並幫助你解決使用 NULL 值可能遇到的一些棘手情況。

例如,如果你要使用這樣的 WHERE 子句查詢:

SELECT * FROM SOME_TABLE
WHERE 1 = 1
複製程式碼

該查詢將返回行(假設 SOME_TABLE 不是空表!),因為表示式“ 1 = 1” 可證明是 true 的……它可以被證明是正確的。

SQL 查詢中的 NULL 值

如果我要說:

SELECT * FROM SOME_TABLE
WHERE 1 = 0
複製程式碼

然後資料庫將看到此情況,並將“ 1 = 0”評估為 false(這意味著該查詢將_永遠不會_返回任何行)。

SQL 查詢中的 NULL 值

但是如果我要說:

SELECT * FROM SOME_TABLE
WHERE 1 = NULL
複製程式碼

資料庫基本上是這樣的:“我不知道這兩個值(1 和我們的黑盒 NULL 值)是否相等”……因此它不返回任何記錄。

SQL 查詢中的 NULL 值

2. 三值邏輯

當 SQL 查詢中有 WHERE 子句時,它可以具有三種不同結果之一:

  • true(它將返回行)
  • false(不會返回行)
  • NULL(未知也不會返回行)

你可能會想,“好吧,既然資料庫對這兩個值的處理完全相同,我為什麼要關心 false 和 null 之間的區別?”

好吧,讓我告訴你哪裡可能遇到麻煩:讓我們介紹一下 NOT() 條件。

如果你要說:

SELECT * FROM SOME_TABLE
WHERE NOT(1 = 1)
複製程式碼

然後,資料庫首先要求值 1 = 1,然後說:“好吧,那顯然是對的。”

但是隨後它將對其應用 NOT() 條件。“當 true 被 NOT() 修飾時,它變成了 false……所以 NOT() 條件導致我們的 WHERE 子句在這裡是 false 的。”

因此,上面的查詢不會返回任何記錄。

SQL 查詢中的 NULL 值

但是,如果你要說:

SELECT * FROM SOME_TABLE
WHERE NOT(1 = 0)
複製程式碼

然後,資料庫首先計算表示式 1 = 0,並說:“那顯然是 false 的。”

但是然後它將應用 NOT() 條件,這將給我們相反的結果,因此它變為 true

因此此查詢將返回記錄!

SQL 查詢中的 NULL 值

如果我發出以下查詢怎麼辦?

SELECT * FROM SOME_TABLE
WHERE NOT(1 = NULL)
複製程式碼

資料庫首先要評估 1 = NULL。(請記住,它將把 NULL 當作一個未知值!)

它會說:“我不能說 1 是否等於 NULL,因為我不知道 NULL(未知)值是什麼。”

因此,它不會產生 true 的結果也不會產生 false 的結果 – 而是會產生 NULL(未知)結果。

NULL 結果將由 NOT() 運算子修飾。

每當你使用 NULL 並將其置於 NOT() 條件時……結果就是另一個 NULL!(未知的反面是……嗯……另一個未知)。

SQL 查詢中的 NULL 值

因此,NOT() 運算子對 null 條件不做任何事情。

所以這些查詢中的……

SELECT * FROM SOME_TABLE
WHERE NOT(1 = NULL)
複製程式碼
SELECT * FROM SOME_TABLE
WHERE 1 = NULL
複製程式碼

…將不返回任何記錄…即使它們是相反的!

SQL 查詢中的 NULL 值

3. NULL 和 NOT IN

如果我使用 WHERE 子句發出這樣的查詢:

SELECT * FROM SOME_TABLE
WHERE 1 IN (1, 2, 3, 4, NULL)
複製程式碼

…那麼顯然 WHERE 子句將是 true 的,由於 1 在我們的 IN 列表中,所以該查詢將返回記錄…

SQL 查詢中的 NULL 值

但是如果我要說:

SELECT * FROM SOME_TABLE
WHERE 1 NOT IN (1, 2, 3, 4, NULL)
複製程式碼

那麼顯然這將是 false 的,該查詢將永遠不會返回記錄,因為數字 1 出現在我們的 IN 列表中,並且我們說“ NOT IN”…

SQL 查詢中的 NULL 值

現在,如果我要說這樣的話怎麼辦?

SELECT * FROM SOME_TABLE
WHERE 5 NOT IN (1, 2, 3, 4, NULL)
複製程式碼

此 WHERE 子句將永遠不會返回任何記錄,因為它不是真正的可證明(它不能被證明是 true 的)。數字 5 沒有明確出現在“ IN”列表中 - 但是 5 可能在我們的“黑盒” NULL 值內(資料庫不一定知道 NULL 的值是什麼)。

這將產生 NULL 結果(表示未知結果),因此 WHERE 子句永遠不會返回任何記錄。

SQL 查詢中的 NULL 值

這就是為什麼將 NULL 值等效為未知值很重要的原因 - 每當你編寫複雜的SQL查詢時,它都會為你提供幫助。

希望你現在已經準備好處理 SQL 查詢中的 NULL 值!有關 SQL,Oracle 資料庫以及使查詢執行更快的更多資訊,請訪問  blog.tuningsql.com

資料

實際例子 ?的 SQL 檔案

CREATE TABLE `user` (
  `id` int(25) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `age` int(32) DEFAULT NULL,
  `sex` varchar(255) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4;

INSERT INTO `test`.`user`(`id`, `name`, `age`, `sex`, `password`) VALUES (2, '小白', 1, '0', '333');
INSERT INTO `test`.`user`(`id`, `name`, `age`, `sex`, `password`) VALUES (3, 'white', 12, '0', '111');
INSERT INTO `test`.`user`(`id`, `name`, `age`, `sex`, `password`) VALUES (4, 'white', NULL, '0', '222');
複製程式碼

參考文章

神奇的 SQL 之溫柔的陷阱 → 三值邏輯 與 NULL !

相關文章