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

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

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

1. 前言

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

2. 兩種 Null

  • 表示未知 (unknown):“不知道戴墨鏡的人眼睛是什么顏色”這種情況為例,這個人的眼睛肯定是有顏色的,但是如果他不摘掉眼鏡,別人就不知道他的眼睛是什么顏色。這就叫作未知。
  • 表示不適用 (not applicable 或 inapplicable):“不知道冰箱的眼睛是什么顏色”則屬于“不適用”。因為冰箱根本就沒有眼睛,所以“眼睛的顏色”這一屬性并不適用于冰箱。

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

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

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

“我們先從定義一個表示‘雖然丟失了,但卻適用的值’的標(biāo)記開始。我們把它叫作 A-Mark。這個標(biāo)記在關(guān)系數(shù)據(jù)庫里既不被當(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)

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

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

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

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

4. 第三個真值 “unknown”

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

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

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

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

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

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

6. “排中律” 不再成立

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

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

但是在SQL中并不是這個樣:

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

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

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

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

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

7. CASE 表達式和 NULL

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

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

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

8. NOT IN 和 NOT EXISTS 不是等價的

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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


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

9. 限定謂詞和 NULL

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

如果山田年齡不詳,就會有問題了。

--1. 執(zhí)行子查詢獲取年齡列表
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 使用“<”后,結(jié)果變?yōu)?unknown
SELECT *
FROM Class_A
WHERE (age < 22) AND (age < 23) AND unknown;

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

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

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

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

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

區(qū)分含義:

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

Q1 和 Q2 不等價的情況:

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

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

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

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

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

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

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

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

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

相關(guān)文章

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    MySql 錯誤Incorrect string value for column

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

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

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

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

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

最新評論