SQL 查詢中的 NULL 值

image

本文通過(guò)各種 SQL 小例子,解釋 NULL 值的用途和帶來(lái)的問(wèn)題。

英語(yǔ)原文地址:https://mitchum.blog/null-values-in-sql-queries/

作者:MITCHUM

翻譯:高行行

參考翻譯文章:https://blog.csdn.net/lnotime/article/details/104847946

小結(jié):

  • SQL 里的 NULL 和其他編程語(yǔ)言里的 NULL 是完全不同的東西
  • 在 SQL 中 NULL 為未知

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

今天的帖子是關(guān)于 SQL 中的 NULL 值的,由我的朋友兼數(shù)據(jù)庫(kù)向?qū)?Kaley 提供。如果你想了解有關(guān) SQL,Oracle 數(shù)據(jù)庫(kù)以及使查詢運(yùn)行更快的更多信息,請(qǐng)?jiān)L問(wèn)他的網(wǎng)站。


這是一個(gè)使很多萌新開(kāi)發(fā)人員陷入困境的話題-SQL 查詢中 NULL 值的概念。

每當(dāng)你向數(shù)據(jù)庫(kù)發(fā)出SQL查詢時(shí)……你想知道一列中是否包含 NULL 值……編寫查詢以查到結(jié)果的正確方式是什么?

你應(yīng)該使用這樣的查詢嗎?

SELECT * FROM SOME_TABLE
WHERE SOME_COLUMN = NULL

要么!你應(yīng)該使用這樣的查詢嗎?

SELECT * FROM SOME_TABLE
WHERE SOME_COLUMN IS NULL

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

下圖為實(shí)際的查詢例子 ??

[圖片上傳失敗...(image-3f58f1-1586060321607)]

[圖片上傳失敗...(image-a119ac-1586060321607)]

[圖片上傳失敗...(image-e0306a-1586060321607)]

為什么呢?

為什么其他的比較都不用 IS 關(guān)鍵字呢?

如果我們想知道一個(gè)字段是否等于 1,我們可以使用如下的 WHERE 子句:

WHERE SOME_COLUMN = 1

那么為什么我們?cè)?strong>IS關(guān)鍵字上使用 NULL 值呢?為什么我們需要區(qū)別對(duì)待 NULL ?

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

1. Null 為未知

在大多數(shù)數(shù)據(jù)庫(kù)中,NULL 和空字符串(由雙撇號(hào) "" 或 '' 表示)之間存在差異。

但是,并非所有數(shù)據(jù)庫(kù)都這樣:例如,Oracle 數(shù)據(jù)庫(kù)不允許你使用空字符串。任何時(shí)候 Oracle 數(shù)據(jù)庫(kù)看到一個(gè)空字符串,它都會(huì)自動(dòng)將空字符串轉(zhuǎn)換為 NULL 值。

但是,對(duì)于大多數(shù)其他數(shù)據(jù)庫(kù),NULL 值與空字符串的處理方式不同:

  • 空字符串被視為沒(méi)有值的已知值。
  • 將 NULL 值視為未知值

舉個(gè)例子,就好像問(wèn):美國(guó)總統(tǒng)西奧多·羅斯福的中間名是什么?

  • 一種答案可能是:“嗯,我不知道西奧多·羅斯福的中間名是什么?!?/strong>(此想法可以由 Theodore Roosevelt 的記錄的 MIDDLE_NAME 列中的 NULL 值表示,即中間名字段為 NULL)
  • 另一種答案可能是**“西奧多·羅斯??偨y(tǒng)實(shí)際上沒(méi)有中間名。他的父母從未給他起過(guò)中間名,我知道的事實(shí)就是西奧多·羅斯福(Theodore Roosevelt)沒(méi)有中間名。 **(你可以通過(guò)在 MIDDLE_NAME 列中輸入一個(gè)空字符串或 '' 來(lái)表示,即中間名字段為空字符串)

Oracle 數(shù)據(jù)庫(kù)是最顯著的例外,其中這兩個(gè)值實(shí)際上都將由 NULL 表示-除 Oracle 以外的大多數(shù)數(shù)據(jù)庫(kù)對(duì) NULL 和空字符串的處理方式都非常不同。

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

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

SELECT * FROM SOME_TABLE
WHERE 1 = 1

該查詢將返回行(假設(shè) SOME_TABLE 不是空表?。?yàn)楸磉_(dá)式“ 1 = 1” 可證明是 true 的……它可以被證明是正確的。

image
image

如果我要說(shuō):

SELECT * FROM SOME_TABLE
WHERE 1 = 0

然后數(shù)據(jù)庫(kù)將看到此情況,并將“ 1 = 0”評(píng)估為 false(這意味著該查詢將永遠(yuǎn)不會(huì)返回任何行)。

image
image

但是如果我要說(shuō):

SELECT * FROM SOME_TABLE
WHERE 1 = NULL

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

image
image

2. 三值邏輯

當(dāng) SQL 查詢中有 WHERE 子句時(shí),它可以具有三種不同結(jié)果之一:

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

你可能會(huì)想,“好吧,既然數(shù)據(jù)庫(kù)對(duì)這兩個(gè)值的處理完全相同,我為什么要關(guān)心 false 和 null 之間的區(qū)別?”

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

如果你要說(shuō):

SELECT * FROM SOME_TABLE
WHERE NOT(1 = 1)

然后,數(shù)據(jù)庫(kù)首先要求值 1 = 1,然后說(shuō):“好吧,那顯然是對(duì)的。”

但是隨后它將對(duì)其應(yīng)用 NOT() 條件。“當(dāng) true 被 NOT() 修飾時(shí),它變成了 false……所以 NOT() 條件導(dǎo)致我們的 WHERE 子句在這里是 false 的?!?/p>

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

[圖片上傳失敗...(image-e9f5e4-1586060321607)]

但是,如果你要說(shuō):

SELECT * FROM SOME_TABLE
WHERE NOT(1 = 0)

然后,數(shù)據(jù)庫(kù)首先計(jì)算表達(dá)式 1 = 0,并說(shuō):“那顯然是 false 的?!?/p>

但是然后它將應(yīng)用 NOT() 條件,這將給我們相反的結(jié)果,因此它變?yōu)?true。

因此此查詢將返回記錄!

[圖片上傳失敗...(image-cf44f3-1586060321607)]

如果我發(fā)出以下查詢?cè)趺崔k?

SELECT * FROM SOME_TABLE
WHERE NOT(1 = NULL)

數(shù)據(jù)庫(kù)首先要評(píng)估 1 = NULL。(請(qǐng)記住,它將把 NULL 當(dāng)作一個(gè)未知值?。?/p>

它會(huì)說(shuō):“我不能說(shuō) 1 是否等于 NULL,因?yàn)槲也恢?NULL(未知)值是什么?!?/p>

因此,它不會(huì)產(chǎn)生 true 的結(jié)果也不會(huì)產(chǎn)生 false 的結(jié)果 – 而是會(huì)產(chǎn)生 NULL(未知)結(jié)果。

NULL 結(jié)果將由 NOT() 運(yùn)算符修飾。

每當(dāng)你使用 NULL 并將其置于 NOT() 條件時(shí)……結(jié)果就是另一個(gè) NULL!(未知的反面是……嗯……另一個(gè)未知)。

image
image

因此,NOT() 運(yùn)算符對(duì) null 條件不做任何事情。

所以這些查詢中的……

SELECT * FROM SOME_TABLE
WHERE NOT(1 = NULL)
SELECT * FROM SOME_TABLE
WHERE 1 = NULL

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

image
image

3. NULL 和 NOT IN

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

SELECT * FROM SOME_TABLE
WHERE 1 IN (1, 2, 3, 4, NULL)

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

[圖片上傳失敗...(image-92c86b-1586060321607)]

但是如果我要說(shuō):

SELECT * FROM SOME_TABLE
WHERE 1 NOT IN (1, 2, 3, 4, NULL)

那么顯然這將是 false 的,該查詢將永遠(yuǎn)不會(huì)返回記錄,因?yàn)閿?shù)字 1 出現(xiàn)在我們的 IN 列表中,并且我們說(shuō)“ NOT IN”…

[圖片上傳失敗...(image-ffae2d-1586060321607)]

現(xiàn)在,如果我要說(shuō)這樣的話怎么辦?

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

此 WHERE 子句將永遠(yuǎn)不會(huì)返回任何記錄,因?yàn)樗皇钦嬲目勺C明(它不能被證明是 true 的)。數(shù)字 5 沒(méi)有明確出現(xiàn)在“ IN”列表中 - 但是 5 可能在我們的“黑盒” NULL 值內(nèi)(數(shù)據(jù)庫(kù)不一定知道 NULL 的值是什么)。

這將產(chǎn)生 NULL 結(jié)果(表示未知結(jié)果),因此 WHERE 子句永遠(yuǎn)不會(huì)返回任何記錄。

[圖片上傳失敗...(image-4dd578-1586060321607)]

這就是為什么將 NULL 值等效為未知值很重要的原因 - 每當(dāng)你編寫復(fù)雜的SQL查詢時(shí),它都會(huì)為你提供幫助。

希望你現(xiàn)在已經(jīng)準(zhǔn)備好處理 SQL 查詢中的 NULL 值!有關(guān) SQL,Oracle 數(shù)據(jù)庫(kù)以及使查詢運(yùn)行更快的更多信息,請(qǐng)?jiān)L問(wèn) blog.tuningsql.com。

資料

實(shí)際例子 ??的 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 !

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1. SQL 簡(jiǎn)介 SQL 的目標(biāo) 理想情況下,數(shù)據(jù)庫(kù)語(yǔ)言應(yīng)允許用戶: 建立數(shù)據(jù)庫(kù)和關(guān)系結(jié)構(gòu) 完成基本數(shù)據(jù)管理任務(wù)...
    板藍(lán)根plank閱讀 2,514評(píng)論 0 11
  • ORACLE自學(xué)教程 --create tabletestone ( id number, --序號(hào)usernam...
    落葉寂聊閱讀 1,243評(píng)論 0 0
  • 什么是數(shù)據(jù)庫(kù)? 數(shù)據(jù)庫(kù)是存儲(chǔ)數(shù)據(jù)的集合的單獨(dú)的應(yīng)用程序。每個(gè)數(shù)據(jù)庫(kù)具有一個(gè)或多個(gè)不同的API,用于創(chuàng)建,訪問(wèn),管理...
    chen_000閱讀 4,143評(píng)論 0 19
  • 第三課: 排序檢索數(shù)據(jù) distinct關(guān)鍵字:distinct 列名1,列名2,列名3DISTINCT 關(guān)鍵字會(huì)...
    VictorBXv閱讀 1,618評(píng)論 0 8
  • 今天看《我是特種兵二》,看了一會(huì)兒,怎么也看不進(jìn)去了,先入為主,第一部分印象太深,很多角色給人的印象太深,到了第二...
    似悅閱讀 149評(píng)論 0 1

友情鏈接更多精彩內(nèi)容