SQL 查詢中的 NULL 值

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

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

做者:MITCHUMsql

翻譯:高行行數據庫

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

小結:編程語言

  • SQL 裏的 NULL 和其餘編程語言裏的 NULL 是徹底不一樣的東西
  • 在 SQL 中 NULL 爲未知

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

今天的帖子是關於 SQL 中的 NULL 值的,由個人朋友兼數據庫嚮導 Kaley 提供。若是你想了解有關 SQL,Oracle 數據庫以及使查詢運行更快的更多信息,請訪問他的網站ui


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

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

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

SELECT * FROM SOME_TABLE
WHERE SOME_COLUMN = NULL
複製代碼

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

SELECT * FROM SOME_TABLE
WHERE SOME_COLUMN IS NULL
複製代碼

…答案是,你應該使用第二個查詢(SOME_COLUMN IS 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 的……它能夠被證實是正確的。

若是我要說:

SELECT * FROM SOME_TABLE
WHERE 1 = 0
複製代碼

而後數據庫將看到此狀況,並將「 1 = 0」評估爲 false(這意味着該查詢將_永遠不會_返回任何行)。

可是若是我要說:

SELECT * FROM SOME_TABLE
WHERE 1 = NULL
複製代碼

數據庫基本上是這樣的:「我不知道這兩個值(1 和咱們的黑盒 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 的。」

所以,上面的查詢不會返回任何記錄。

可是,若是你要說:

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

而後,數據庫首先計算表達式 1 = 0,並說:「那顯然是 false 的。」

可是而後它將應用 NOT() 條件,這將給咱們相反的結果,所以它變爲 true

所以此查詢將返回記錄!

若是我發出如下查詢怎麼辦?

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

數據庫首先要評估 1 = NULL。(請記住,它將把 NULL 看成一個未知值!)

它會說:「我不能說 1 是否等於 NULL,由於我不知道 NULL(未知)值是什麼。」

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

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

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

所以,NOT() 運算符對 null 條件不作任何事情。

因此這些查詢中的……

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

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

3. NULL 和 NOT IN

若是我使用 WHERE 子句發出這樣的查詢:

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

…那麼顯然 WHERE 子句將是 true 的,因爲 1 在咱們的 IN 列表中,因此該查詢將返回記錄…

可是若是我要說:

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

那麼顯然這將是 false 的,該查詢將永遠不會返回記錄,由於數字 1 出如今咱們的 IN 列表中,而且咱們說「 NOT IN」…

如今,若是我要說這樣的話怎麼辦?

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

此 WHERE 子句將永遠不會返回任何記錄,由於它不是真正的可證實(它不能被證實是 true 的)。數字 5 沒有明確出如今「 IN」列表中 - 可是 5 可能在咱們的「黑盒」 NULL 值內(數據庫不必定知道 NULL 的值是什麼)。

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

這就是爲何將 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 !

相關文章
相關標籤/搜索