最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解數(shù)據(jù)庫語言中的null值

 更新時間:2015年04月11日 10:01:24   作者:periscope  
這篇文章主要詳解了數(shù)據(jù)庫語言中的null值,針對MySQL上的實例進行講解,需要的朋友可以參考下

雖然熟練掌握SQL的人對于Null不會有什么疑問,但總結(jié)得很全的文章還是很難找,看到一篇英文版的, 感覺還不錯。

Tony Hoare 在1965年發(fā)明了 null 引用, 并認(rèn)為這是他犯下的“幾十億美元的錯誤”. 即便是50年后的今天, SQL中的 null 值還是導(dǎo)致許多常見錯誤的罪魁禍?zhǔn)?

我們一起來看那些最令人震驚的情況。

 

Null不支持大小/相等判斷

下面的2個查詢,不管表 users 中有多少條記錄,返回的記錄都是0行:
 

select * from users where deleted_at = null;
 
– result: 0 rows
 
select * from users where deleted_at != null;
 
– result: 0 rows

 

怎么會這樣子? 一切只因為 null 是表示一種“未知”的類型。也就是說,用常規(guī)的比較操作符(normal conditional operators)來將 null 與其他值比較是沒有意義的。 Null 也不等于 Null(近似理解: 未知的值不能等于未知的值,兩者間的關(guān)系也是未知,否則數(shù)學(xué)和邏輯上就亂套了)。

– 注意: 下面的SQL適合于MySQL,如果是Oracle,你需要加上 … from dual;

 

select null > 0;
 
– result: null
 
select null < 0;
 
– result: null
 
select null = 0;
 
– result: null
 
select null = null;
 
– result: null
 
select null != null;
 
– result: null

 

將某個值與 null 進行比較的正確方法是使用 is 關(guān)鍵字, 以及 is not 操作符:
 

select * from users
 
where deleted_at is null;
 
– result: 所有被標(biāo)記為刪除的 users

 

如果想要判斷兩列的值是否不相同,則可以使用 is distinct from:
 

select * from users
 
where has_address is distinct from has_photo
 
– result: 地址(address)或照片(photo)兩者只有其一的用戶

 

not in 與 Null

子查詢(subselect)是一種很方便的過濾數(shù)據(jù)的方法。例如,如果想要查詢沒有任何包的用戶,可以編寫下面這樣一個查詢:
 

select * from users 
 
where id not in (select user_id from packages)

 

但此時假若 packages 表中某一行的 user_id 是 null 的話,問題就來了: 返回結(jié)果是空的! 要理解為什么會發(fā)生這種古怪的事情, 我們需要理解SQL編譯器究竟干了些什么. 下面是一個更簡單的示例:
 

select * from users 
 
where id not in (1, 2, null)

 

這個SQL語句會被轉(zhuǎn)換為:
 

select * from users 
 
where id != 1 and id != 2 and id != null

 

我們知道,id != null 結(jié)果是個未知值, null. 而任意值和 null 進行 and 運算的結(jié)果都是 null, 所以相當(dāng)于沒有其他條件. 那么出這種結(jié)果的原因就是 null 的邏輯值不為 true.

如果條件調(diào)換過來, 查詢結(jié)果就沒有問題。 現(xiàn)在我們查詢有package的用戶.
 

select * from users 
 
where id in (select user_id from packages)

 

同樣我們可以使用簡單的例子:
 

select * from users
 
where id in (1, 2, null)

 

這條SQL被轉(zhuǎn)換為:
 

select * from users 
 
where id = 1 or id = 2 or id = null

因為 where 子句中是一串的 or 條件,所以其中某個的結(jié)果為 null 也是無關(guān)緊要的。非真(non-true)值并不影響子句中其他部分的計算結(jié)果,相當(dāng)于被忽略了。

 

Null與排序

在排序時, null 值被認(rèn)為是最大的. 在降序排序時(descending)這會讓你非常頭大,因為 null值排在了最前面。

下面這個查詢是為了根據(jù)得分顯示用戶排名, 但它將沒有得分的用戶排到了最前面!
 

select name, points
 
from users
 
order by 2 desc;
 
– points 為 null 的記錄排在所有記錄之前!

 

解決這類問題有兩種思路。最簡單的一種是用 coalesce 消除 null的影響:
 

– 在輸出時將 null 轉(zhuǎn)換為 0 :
 
select name, coalesce(points, 0)
 
from users
 
order by 2 desc;
 
– 輸出時保留 null, 但排序時轉(zhuǎn)換為 0 :
 
select name, points
 
from users
 
order by coalesce(points, 0) desc;

 

還有一種方式需要數(shù)據(jù)庫的支持,指定排序時將 null 值放在最前面還是最后面:
 

select name, coalesce(points, 0)
 
from users
 
order by 2 desc nulls last;

當(dāng)然, null 也可以用來防止錯誤的發(fā)生,比如處理除數(shù)為0的數(shù)學(xué)運算錯誤。

 

被 0 除

除數(shù)為0是一個非常 egg-painfull 的錯誤。昨天還運行得好好的SQL,突然被0除一下子就出錯了。一個常用的解決方法是先用 case 語句判斷分母(denominator)是否為0,再進行除法運算。

 

select case when num_users = 0 then 0 
 
else total_sales/num_users end;

 

ase 語句的方式其實很難看,而且分母被重復(fù)使用了。如果是簡單的情況還好,如果分母是個很復(fù)雜的表達式,那么悲劇就來了: 很難讀,很難維護和修改,一不小心就是一堆BUG.

這時候我們可以看看 null 的好處. 使用 nullif 使得分母為0時變成 null. 這樣就不再報錯, num_users = 0 時返回結(jié)果變?yōu)?null.
 

select total_sales/nullif(num_users, 0);

 
nullif 是將其他值轉(zhuǎn)為 null, 而Oracle的 nvl 是將 null 轉(zhuǎn)換為其他值。

 

如果不想要 null,而是希望轉(zhuǎn)換為 0 或者其他數(shù), 則可以在前一個SQL的基礎(chǔ)上使用 coalesce函數(shù):
 

select coalesce(total_sales/nullif(num_users, 0), 0);

 
null 再轉(zhuǎn)換回0

 

Conclusion

Tony Hoare 也許會后悔自己的錯誤, 但至少 null 存在的問題很容易地就解決了. 那么快去練練新的大招吧,從此遠(yuǎn)離 null 挖出來的無效大坑(nullifying)!

相關(guān)文章

  • MySQL詳解如何優(yōu)化查詢條件

    MySQL詳解如何優(yōu)化查詢條件

    我們知道從MySQL表中使用SELECT語句來查詢數(shù)據(jù),如需有條件地從表中選取數(shù)據(jù),可將WHERE子句添加到SELECT語句中,本篇我們來看看怎樣優(yōu)化查詢條件
    2022-05-05
  • mysql 登錄時閃退的問題解決方法

    mysql 登錄時閃退的問題解決方法

    這篇文章主要介紹了mysql 登錄時閃退的問題解決方法的相關(guān)資料,mysql 出現(xiàn)閃退問題,很是棘手在做項目的時候,這里對解決這樣的問題提供了解決方案,需要的朋友可以參考下
    2016-11-11
  • MySql8 WITH RECURSIVE遞歸查詢父子集的方法

    MySql8 WITH RECURSIVE遞歸查詢父子集的方法

    這篇文章主要介紹了MySql8 WITH RECURSIVE遞歸查詢父子集的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • MySQL主從復(fù)制之半同步semi-sync?replication

    MySQL主從復(fù)制之半同步semi-sync?replication

    這篇文章主要介紹了MySQL主從復(fù)制之半同步semi-sync?replication,半同步相對于異步復(fù)制而言,提高了數(shù)據(jù)的安全性,同時也造成了一定程度的延遲,這個延遲最少是一個TCP往返的時間。所以,半同步復(fù)制最好在低延時的網(wǎng)絡(luò)中使用,下文詳細(xì)內(nèi)容,需要的小伙伴可以參考一下
    2022-02-02
  • MySQL排序優(yōu)化詳細(xì)解析

    MySQL排序優(yōu)化詳細(xì)解析

    這篇文章主要介紹了MySQL排序優(yōu)化詳細(xì)解析,MySQL有兩種方式生成有序的結(jié)果:1.通過排序操作;2.按索引順序掃描,如果EXPLAIN出來的type列的值為"index",則說明使用了索引掃描來做排序,需要的朋友可以參考下
    2024-01-01
  • SQL替換字符串值的5種常用方法

    SQL替換字符串值的5種常用方法

    這篇文章主要給大家介紹了關(guān)于SQL替換字符串值的5種常用方法,常用SQL的朋友應(yīng)該知道,SQL中一般都會提供一些字符串處理函數(shù),需要的朋友可以參考下
    2023-08-08
  • 利用mysql事務(wù)特性實現(xiàn)并發(fā)安全的自增ID示例

    利用mysql事務(wù)特性實現(xiàn)并發(fā)安全的自增ID示例

    項目中經(jīng)常會用到自增id,比如uid,下面為大家介紹下利用mysql事務(wù)特性實現(xiàn)并發(fā)安全的自增ID,感興趣的朋友可以參考下
    2013-11-11
  • MySQL數(shù)據(jù)庫SELECT查詢表達式解析

    MySQL數(shù)據(jù)庫SELECT查詢表達式解析

    這篇文章主要介紹了MySQL數(shù)據(jù)庫SELECT查詢表達式解析,文中給大家介紹了select_expr 查詢表達式書寫方法,需要的朋友可以參考下
    2018-04-04
  • 在SQL中對同一個字段不同值,進行數(shù)據(jù)統(tǒng)計操作

    在SQL中對同一個字段不同值,進行數(shù)據(jù)統(tǒng)計操作

    這篇文章主要介紹了在SQL中對同一個字段不同值,進行數(shù)據(jù)統(tǒng)計操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-10-10
  • MySQL實現(xiàn)清空分區(qū)表單個分區(qū)數(shù)據(jù)

    MySQL實現(xiàn)清空分區(qū)表單個分區(qū)數(shù)據(jù)

    這篇文章主要介紹了MySQL實現(xiàn)清空分區(qū)表單個分區(qū)數(shù)據(jù)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03

最新評論

鄯善县| 涿州市| 锦州市| 澄江县| 泽州县| 仙游县| 交口县| 府谷县| 武功县| 平潭县| 清原| 峨边| 九龙坡区| 辉县市| 周至县| 依兰县| 安化县| 长岛县| 金湖县| 崇信县| 本溪| 万源市| 石城县| 正镶白旗| 临颍县| 宜都市| 湛江市| 溧水县| 土默特左旗| 友谊县| 临夏县| 甘洛县| 德惠市| 三江| 芷江| 榆社县| 锡林郭勒盟| 木兰县| 黄平县| 浦城县| 马龙县|