在SQL Server中,Null值并不是一個(gè)值,而是表示特定含義,其所表示的含義是“Unknow”,可以理解為未定義或者未知,因此任何與Null值進(jìn)行比對(duì)的二元操作符結(jié)果一定為Null,包括Null值本身。而在SQL Server中,Null值的含義轉(zhuǎn)換為Bool類型的結(jié)果為False。讓我們來(lái)看一個(gè)簡(jiǎn)單的例子,如圖1所示。
圖1.Null值與任何值進(jìn)行對(duì)比結(jié)果都為Null
SQL Server提供了“IS”操作符與Null值做對(duì)比,用于衡量某個(gè)值是否為Null。
那么Not In 的問(wèn)題在哪呢,如圖2所示。
圖2.Not In產(chǎn)生不準(zhǔn)確的值
在圖2中,條件3不屬于Not In后面列表的任意一個(gè),該查詢卻不返回任何值,與預(yù)期的結(jié)果不同,那么具體原因就是Not In子句對(duì)于Null值的處理,在SQL Server中,圖2中所示的Not In子句其實(shí)可以等價(jià)轉(zhuǎn)換為如圖3所示的查詢。
圖3.對(duì)于Not In子句來(lái)說(shuō),可以進(jìn)行等價(jià)轉(zhuǎn)換
在圖3中可以看到Not In可以轉(zhuǎn)換為條件對(duì)于每個(gè)值進(jìn)行不等比對(duì),并用邏輯與連接起來(lái),而前面提到過(guò)Null值與任意其他值做比較時(shí),結(jié)果永遠(yuǎn)為Null,在Where條件中也就是False,因此3<>null就會(huì)導(dǎo)致不返回任何行,導(dǎo)致Not In子句產(chǎn)生的結(jié)果在意料之外。
因此,Not In子句如果來(lái)自于某個(gè)表或者列表很長(zhǎng),其中大量值中即使存在一個(gè)Null值,也會(huì)導(dǎo)致最終結(jié)果不會(huì)返回任何數(shù)據(jù)。
解決辦法
解決辦法就是不使用Not In,而使用Not Exists作為替代。Exists的操作符不會(huì)返回Null,只會(huì)根據(jù)子查詢中的每一行決定返回True或者False,當(dāng)遇到Null值時(shí),只會(huì)返回False,而不會(huì)由某個(gè)Null值導(dǎo)致整個(gè)子查詢表達(dá)式為Null。對(duì)于圖2中所示的查詢,我們可以改寫為子查詢,如圖4所示。
圖4.Not Exists可以正確返回結(jié)果