欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

一文詳解SQL?中的三值邏輯

 更新時(shí)間:2022年09月19日 09:59:46   作者:Wang1  
這篇文章主要介紹了一文詳解SQL中的三值邏輯,文章圍繞主題展開(kāi)對(duì)三值邏輯Null的詳細(xì)介紹,感興趣的小伙伴可以參考一下

1. 前言

大多數(shù)編程語(yǔ)言都是基于二值邏輯的,即邏輯真值只有真和假兩個(gè)。而 SQL 語(yǔ)言則采用一種特別的邏輯體系——三值邏輯,即邏輯真值除了真和假,而 SQL 語(yǔ)言里,除此之外還有第三個(gè)值 unknown ,因此這種邏輯體系被稱為三值邏輯(three-valued-logic)。

2. 兩種 Null

  • 表示未知 (unknown):“不知道戴墨鏡的人眼睛是什么顏色”這種情況為例,這個(gè)人的眼睛肯定是有顏色的,但是如果他不摘掉眼鏡,別人就不知道他的眼睛是什么顏色。這就叫作未知。
  • 表示不適用 (not applicable 或 inapplicable):“不知道冰箱的眼睛是什么顏色”則屬于“不適用”。因?yàn)楸涓揪蜎](méi)有眼睛,所以“眼睛的顏色”這一屬性并不適用于冰箱。

“冰箱的眼睛的顏色”這種說(shuō)法和“圓的體積”“男性的分娩次數(shù)”一樣,都是沒(méi)有意義的。平時(shí),我們習(xí)慣了說(shuō)“不知道”,但是“不知道”也分很多種。“不適用”這種情況下的 NULL ,在語(yǔ)義上更接近于“無(wú)意義”,而不是“不確定”。

總結(jié):“未知”指的是“雖然現(xiàn)在不知道,但加上某些條件后就可以知道”;而“不適用”指的是“沒(méi)有辦法知道”。

3. 為什么是 is Null 而不是 = Null ?

“我們先從定義一個(gè)表示‘雖然丟失了,但卻適用的值’的標(biāo)記開(kāi)始。我們把它叫作 A-Mark。這個(gè)標(biāo)記在關(guān)系數(shù)據(jù)庫(kù)里既不被當(dāng)作值(value),也不被當(dāng)作變量 (variable)。”(E.F. Codd,The Relational Model for Database Management :Version 2 , P.173) “關(guān)于 NULL 的很重要的一件事情是,NULL 并不是值。”(C.J. Date, An Intruction To Database System (6th edition ), P.619)

對(duì) NULL 使用比較謂詞后得到的結(jié)果總是 unknown 。而查詢結(jié)果只會(huì)包含 WHERE 子句里的判斷結(jié)果為 true 的行,不會(huì)包含判斷結(jié)果為 false 和 unknown 的行。不只是等號(hào),對(duì) NULL 使用其他比較謂詞,結(jié)果也都是一樣的。

-- 以下的式子都會(huì)被判為 unknown
1 = NULL
2 > NULL
3 < NULL
4 <> NULL
NULL = NULL

那么,為什么對(duì) NULL 使用比較謂詞后得到的結(jié)果永遠(yuǎn)不可能為真呢?這是因?yàn)椋琋ULL 既不是值也不是變量。NULL 只是一個(gè)表示“沒(méi)有值”的標(biāo)記,而比較謂詞只適用于值。因此,對(duì)并非值的 NULL 使用比較謂詞本來(lái)就是沒(méi)有意義的。(Null只是一個(gè)作為區(qū)分的標(biāo)記,并不是一個(gè)值)

“列的值為 NULL ”“NULL 值”這樣的說(shuō)法本身就是錯(cuò)誤的。因?yàn)?NULL 不是值,所以不在定義域(domain)中。相反,如果有人認(rèn)為 NULL 是值,那么請(qǐng)區(qū)分一下:它是什么類型的值?關(guān)系數(shù)據(jù)庫(kù)中存在的值必然屬于某種類型,比如字符型或數(shù)值型等。所以,假如 NULL 是值,那么它就必須屬于某種類型。( SQL 里的 NULL 和其他編程語(yǔ)言里的 NULL 是完全不同的東西)

4. 第三個(gè)真值 “unknown”

因關(guān)系數(shù)據(jù)庫(kù)采用了 NULL 而被引入了 “第三個(gè)真值”。這里有一點(diǎn)需要注意:真值 unknown 和作為 NULL 的一種的 UNKNOWN (未知)是不同的東西。前者是明確的布爾型的真值,后者既不是值也不是變量。(下文使用 unknown 表示 真值,UNKNOWN 表示 代表Null的一個(gè) 標(biāo)記)

舉個(gè)栗子: unknown = unknown 判定為 true 而 UNKNOWN = UNKNOWN ( 也就是 Null = Null ) 判定為 unknown

5. 包含三值邏輯的真值表

當(dāng)兩個(gè)值進(jìn)行邏輯判斷的時(shí)候的優(yōu)先級(jí),優(yōu)先級(jí)高的真值會(huì)決定計(jì)算結(jié)果:

  • AND 的情況: false > unknown > true
  • OR 的情況: true > unknown > false

舉個(gè)栗子: true AND unknown ,因?yàn)?unknown 的優(yōu)先級(jí)更高,所以結(jié)果是 unknown 。而 true OR unknown 的話,因?yàn)?true 優(yōu)先級(jí)更高,所以結(jié)果是 true 。

6. “排中律” 不再成立

“把命題和它的否命題通過(guò)‘或者’連接而成的命題全都是真命題” 這個(gè)命題在二值邏輯中被稱為排中律(Law of Excluded Middle)。顧名思義,排中律就是指不認(rèn)可中間狀態(tài),對(duì)命題真?zhèn)蔚呐卸ê诎追置?,是古典邏輯學(xué)的重要原理。

舉個(gè)栗子:現(xiàn)實(shí)生活中 一個(gè)學(xué)生 是20歲 或者 不是20歲,不會(huì)有第三種情況。

但是在SQL中并不是這個(gè)樣:

-- 查詢年齡是20 歲或者不是20 歲的學(xué)生
SELECT *
FROM Students
WHERE age = 20 OR age <> 20;

在現(xiàn)實(shí)生活中,上面的查詢條件應(yīng)該包含所有的學(xué)生,但是這里的執(zhí)行結(jié)果并不會(huì)查詢到約翰。

--- 當(dāng)查詢到約翰哪一行時(shí)的判定
WHERE Null = 20 OR Null <> 20

--- 根據(jù)上文的描述,該條件會(huì)轉(zhuǎn)換為
WHERE unknown OR unknown   等同于 WHERE unknown

若要查到所有學(xué)生需要再加上一個(gè)條件:OR age IS NULL

7. CASE 表達(dá)式和 NULL

CASE col_1
    WHEN 1 THEN '○'
    WHEN NULL THEN '×'
END

上面的這個(gè)CASE表達(dá)式會(huì)在 col_1 為 1 時(shí)返回  、為 NULL 時(shí)返回 × 嗎?顯然始終不會(huì)返回 x 因?yàn)榈诙€(gè) WHEN 子句是 col_1 = NULL 的縮寫(xiě)形式,根據(jù)上文的描述 col_1 = NULL 始終會(huì)返回 unknown 而 CASE 表達(dá)式的判斷方法與 WHERE 子句一樣,只認(rèn)可真值為 true 的條件,所以 x 并不會(huì)出現(xiàn)。下面才是正確的寫(xiě)法:

CASE 
    WHEN col_1 = 1 THEN '○'
    WHEN col_1 IS NULL THEN '×'
END

8. NOT IN 和 NOT EXISTS 不是等價(jià)的

在對(duì) SQL 語(yǔ)句進(jìn)行性能優(yōu)化時(shí),經(jīng)常用到的一個(gè)技巧是將 IN 改寫(xiě)成EXISTS 。這是等價(jià)改寫(xiě),并沒(méi)有什么問(wèn)題。問(wèn)題在于,將 NOT IN 改寫(xiě)成 NOT EXISTS 時(shí),結(jié)果未必一樣。

查詢 “與 B 班住在東京的學(xué)生年齡不同的 A 班學(xué)生” 。也就是說(shuō),希望查詢到的是拉里和伯杰。

-- 查詢與 B 班住在東京的學(xué)生年齡不同的 A 班學(xué)生的 SQL 語(yǔ)句
SELECT *
FROM Class_A
WHERE age NOT IN ( SELECT age FROM Class_B WHERE city = '東京' );

這條 SQL 語(yǔ)句真的能正確地查詢到這兩名學(xué)生嗎?遺憾的是不能。結(jié)果是空,查詢不到任何數(shù)據(jù)。根據(jù)前文所說(shuō)的規(guī)則推導(dǎo)一下吧:

--1. 執(zhí)行子查詢,獲取年齡列表
SELECT *
FROM Class_A
WHERE age NOT IN (22, 23, NULL);
--2. 用 NOT 和 IN 等價(jià)改寫(xiě) NOT IN
SELECT *
FROM Class_A
WHERE NOT age IN (22, 23, NULL);

--3. 用 OR 等價(jià)改寫(xiě)謂詞 IN
SELECT *
FROM Class_A
WHERE NOT ( (age = 22) OR (age = 23) OR (age = NULL) );

--4. 使用德 · 摩根定律等價(jià)改寫(xiě)
SELECT *
FROM Class_A
WHERE NOT (age = 22) AND NOT(age = 23) AND NOT (age = NULL);

--5. 用<> 等價(jià)改寫(xiě) NOT 和 =
SELECT *
FROM Class_A
WHERE (age <> 22) AND (age <> 23) AND (age <> NULL);

--6. 對(duì)NULL 使用<> 后,結(jié)果為unknown
SELECT *
FROM Class_A
WHERE (age <> 22) AND (age <> 23) AND unknown;

--7.如果AND 運(yùn)算里包含unknown,則結(jié)果不為true
SELECT *
FROM Class_A
WHERE false 或 unknown;

所以 上述查詢語(yǔ)句 查詢不到任何數(shù)據(jù)。為了得到正確的結(jié)果,需要使用 EXISTS 謂詞。

-- 正確的SQL 語(yǔ)句:拉里和伯杰將被查詢到
SELECT *
FROM Class_A A
WHERE NOT EXISTS ( SELECT * FROM Class_B B WHERE A.age = B.age AND B.city = '東京' );

--1. 在子查詢里和NULL 進(jìn)行比較運(yùn)算
SELECT *
FROM Class_A A
WHERE NOT EXISTS ( SELECT * FROM Class_B B WHERE A.age = NULL AND B.city = '東京' );

--2. 對(duì)NULL 使用“=”后,結(jié)果為 unknown
SELECT *
FROM Class_A A
WHERE NOT EXISTS ( SELECT * FROM Class_B B WHERE unknown AND B.city = '東京' );


--3. 如果AND 運(yùn)算里包含unknown,結(jié)果不會(huì)是true
SELECT *
FROM Class_A A
WHERE NOT EXISTS ( SELECT * FROM Class_B B WHERE false 或 unknown);


--4. 子查詢沒(méi)有返回結(jié)果,因此相反地,NOT EXISTS 為true
SELECT *
FROM Class_A A
WHERE true;

9. 限定謂詞和 NULL

-- 查詢比 B 班住在東京的所有學(xué)生年齡都小的A 班學(xué)生 這里會(huì)正常返回 拉里
SELECT *
FROM Class_A
WHERE age < ALL ( SELECT age FROM Class_B WHERE city = '東京' );

如果山田年齡不詳,就會(huì)有問(wèn)題了。

--1. 執(zhí)行子查詢獲取年齡列表
SELECT *
FROM Class_A
WHERE age < ALL ( 22, 23, NULL);


--2. 將ALL 謂詞等價(jià)改寫(xiě)為AND
SELECT *
FROM Class_A
WHERE (age < 22) AND (age < 23) AND (age < NULL);


--3. 對(duì)NULL 使用“<”后,結(jié)果變?yōu)?unknown
SELECT *
FROM Class_A
WHERE (age < 22) AND (age < 23) AND unknown;

--4. 如果AND 運(yùn)算里包含unknown,則結(jié)果不為true
SELECT *
FROM Class_A
WHERE false 或 unknown;

10. 限定謂詞和極值函數(shù)不是等價(jià)的

將 9 中的表 Class_B 中 山田的年齡改為Null,執(zhí)行下面的查詢

-- 查詢比B 班住在東京的年齡最小的學(xué)生還要小的A 班學(xué)生 
SELECT *
FROM Class_A
WHERE age < ( SELECT MIN(age) FROM Class_B WHERE city = '東京' );

這里仍能正確查詢出拉里和伯杰,這是因?yàn)?,極值函數(shù)在統(tǒng)計(jì)時(shí)會(huì)把為 NULL 的數(shù)據(jù)排除掉。使用極值函數(shù)能使 Class_B 這張表里看起來(lái)就像不存在 NULL 一樣。

區(qū)分含義:

  • ALL 謂詞:他的年齡比在東京住的所有學(xué)生都小 Q1
  • 極值函數(shù):他的年齡比在東京住的年齡最小的學(xué)生還要小 Q2

Q1 和 Q2 不等價(jià)的情況:

  • 表里存在 NULL 時(shí)它們是不等價(jià)的
  • 謂詞(或者函數(shù))的輸入為空集的情況

這里說(shuō)明一下情況2:B 班里沒(méi)有學(xué)生住在東京。這時(shí),使用 ALL 謂詞的SQL 語(yǔ)句會(huì)查詢到 A 班的所有學(xué)生。然而,用極值函數(shù)查詢時(shí)一行數(shù)據(jù)都查詢不到。這是因?yàn)?,極值函數(shù)在輸入為空表(空集)時(shí)會(huì)返回 NULL 。

--1. 極值函數(shù)返回NULL
SELECT *
FROM Class_A
WHERE age < NULL;

--2. 對(duì)NULL 使用“<”后結(jié)果為 unknown
SELECT *
FROM Class_A
WHERE unknown;

11. 聚合函數(shù)和 Null

實(shí)際上,當(dāng)輸入為空表時(shí)返回 NULL 的不只是極值函數(shù),COUNT 以外的聚合函數(shù)也是如此。

-- 查詢比住在東京的學(xué)生的平均年齡還要小的A 班學(xué)生的SQL 語(yǔ)句?
SELECT *
FROM Class_A
WHERE age < ( SELECT AVG(age) FROM Class_B WHERE city = '東京' );

沒(méi)有住在東京的學(xué)生時(shí),AVG 函數(shù)返回 NULL 。因此,外側(cè)的 WHERE 子句永遠(yuǎn)是 unknown ,也就查詢不到行。

到此這篇關(guān)于一文詳解SQL 中的三值邏輯的文章就介紹到這了,更多相關(guān)SQL三值邏輯內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • MySQL中replace into與replace區(qū)別詳解

    MySQL中replace into與replace區(qū)別詳解

    本文主要介紹了MySQL中replace into與replace區(qū)別詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • mysql單字段多值分割和合并的處理方法

    mysql單字段多值分割和合并的處理方法

    這篇文章主要給大家介紹了關(guān)于mysql單字段多值分割和合并的處理方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • Mysql5.7中JSON操作函數(shù)使用說(shuō)明

    Mysql5.7中JSON操作函數(shù)使用說(shuō)明

    本文給大家分享的是在mysql5.7中操作json的函數(shù)的使用方法以及相關(guān)示例,非常的實(shí)用,有需要的小伙伴可以參考下
    2017-07-07
  • MySQL中的分組和多表連接詳解

    MySQL中的分組和多表連接詳解

    這篇文章主要介紹了MySQL中的分組和多表連接的相關(guān)操作,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧
    2025-04-04
  • mysql數(shù)據(jù)庫(kù)備份命令分享(mysql壓縮數(shù)據(jù)庫(kù)備份)

    mysql數(shù)據(jù)庫(kù)備份命令分享(mysql壓縮數(shù)據(jù)庫(kù)備份)

    這篇文章主要介紹了mysql數(shù)據(jù)庫(kù)備份常用語(yǔ)句,包括數(shù)據(jù)庫(kù)壓縮備份、備份多個(gè)MySQL數(shù)據(jù)庫(kù)、備份多個(gè)MySQL數(shù)據(jù)庫(kù)、將數(shù)據(jù)庫(kù)轉(zhuǎn)移到新服務(wù)器等語(yǔ)句
    2014-01-01
  • win10下安裝兩個(gè)MySQL5.6.35數(shù)據(jù)庫(kù)

    win10下安裝兩個(gè)MySQL5.6.35數(shù)據(jù)庫(kù)

    這篇文章主要為大家詳細(xì)介紹了win10下兩個(gè)MySQL5.6.35數(shù)據(jù)庫(kù)安裝教程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • 深度解析MySQL 5.7之中文全文檢索

    深度解析MySQL 5.7之中文全文檢索

    InnoDB默認(rèn)的全文索引parser非常合適于Latin,因?yàn)長(zhǎng)atin是通過(guò)空格來(lái)分詞的。但對(duì)于像中文,日文和韓文來(lái)說(shuō),沒(méi)有這樣的分隔符。一個(gè)詞可以由多個(gè)字來(lái)組成,所以我們需要用不同的方式來(lái)處理。在MySQL 5.7.6中我們能使用一個(gè)新的全文索引插件來(lái)處理它們:n-gram parser。
    2016-12-12
  • MySql 錯(cuò)誤Incorrect string value for column

    MySql 錯(cuò)誤Incorrect string value for column

    能使用中文進(jìn)行搜索,但是insert into 中文是可以的。我的數(shù)據(jù)庫(kù)和數(shù)據(jù)表中所有的charset都是設(shè)置的utf8。
    2010-12-12
  • mysql查詢結(jié)果輸出到文件的方法

    mysql查詢結(jié)果輸出到文件的方法

    下面小編就為大家?guī)?lái)一篇mysql查詢結(jié)果輸出到文件的方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-01-01
  • 在MySQL中創(chuàng)建帶有IN和OUT參數(shù)的存儲(chǔ)過(guò)程的方法

    在MySQL中創(chuàng)建帶有IN和OUT參數(shù)的存儲(chǔ)過(guò)程的方法

    這篇文章主要介紹了在MySQL中創(chuàng)建帶有IN和OUT參數(shù)的存儲(chǔ)過(guò)程的方法,在一定程度上簡(jiǎn)化了操作,需要的朋友可以參考下
    2015-06-06

最新評(píng)論