日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

开发随笔——NOT IN vs NOT EXISTS

發布時間:2025/3/19 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 开发随笔——NOT IN vs NOT EXISTS 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
原文: 開發隨筆——NOT IN vs NOT EXISTS

原文出處:?http://blog.csdn.net/dba_huangzj/article/details/31374037 ?轉載請引用

之前在論壇中見到一個針對in/exists的討論,原帖懶得找了,這里介紹一下最近的學習小結:

NOT IN和NOT EIXTS在對允許為null的列查詢時會有一定的風險。特別是NOT IN,如果子查詢包含了最少一個NULL,會出現非預期的結果。下面做一個演示。

?

IF OBJECT_ID('ShipmentItems', 'U') IS NOT NULL DROP TABLE dbo.ShipmentItems; GO CREATE TABLE dbo.ShipmentItems ( ShipmentBarcode VARCHAR(30) NOT NULL , Description VARCHAR(100) NULL , Barcode VARCHAR(30) NOT NULL ); GO INSERT INTO dbo.ShipmentItems ( ShipmentBarcode , Barcode , Description ) SELECT '123456' , '1010203' , 'Some cool widget' UNION ALL SELECT '123654' , '1010203' , 'Some cool widget' UNION ALL SELECT '123654' , '1010204' , 'Some cool stuff for some gadget'; GO -- retrieve all the items from shipment 123654 -- that are not shipped in shipment 123456 SELECT Barcode FROM dbo.ShipmentItems WHERE ShipmentBarcode = '123654' AND Barcode NOT IN ( SELECT Barcode FROM dbo.ShipmentItems WHERE ShipmentBarcode = '123456' ); /* Barcode ------------------------------ 1010204 */

?

可以看出得到了期待結果。下面看看修改表結構,允許列為null的情況:

ALTER TABLE dbo.ShipmentItems ALTER COLUMN Barcode VARCHAR(30) NULL; INSERT INTO dbo.ShipmentItems ( ShipmentBarcode , Barcode , Description ) SELECT '123456' , NULL , 'Users manual for some gadget'; GO SELECT Barcode FROM dbo.ShipmentItems WHERE ShipmentBarcode = '123654' AND Barcode NOT IN ( SELECT Barcode FROM dbo.ShipmentItems WHERE ShipmentBarcode = '123456' ); /* Barcode ------------------------------ */

很多人會覺得這是一個bug,有時候能查出數據,有時候卻不能。但是實際上不是bug,當NOT IN子句返回最少一個NULL時,查詢會返回空,下面的語句能更好地說明這個想法:

SELECT CASE WHEN 1 NOT IN ( 2, 3 ) THEN 'True' ELSE 'Unknown or False' END , CASE WHEN 1 NOT IN ( 2, 3, NULL ) THEN 'True' ELSE 'Unknown or False' END; /* ---- ---------------- True Unknown or False */

實際上,由于IN的本質是OR操作,所以:


SELECT CASE WHEN 1 IN ( 1, 2, NULL ) THEN 'True' ELSE 'Unknown or False' END ;

中,1 in 1,也就是為TRUE,所以返回true,這個語句的邏輯實際上是:

SELECT CASE WHEN ( 1 = 1 ) OR ( 1 = 2 ) OR ( 1 = NULL ) THEN 'True' ELSE 'Unknown or False' END ;

當使用NOT IN 時,如下面的語句:

SELECT CASE WHEN 1 NOT IN ( 1, 2, NULL ) THEN 'True' ELSE 'Unknown or False' END ;

會轉變成:

SELECT CASE WHEN NOT ( ( 1 = 1 ) OR ( 1 = 2 ) OR ( 1 = NULL ) ) THEN 'True' ELSE 'Unknown or False' END ;

根據離散數學的概念,可以轉換為:

SELECT CASE WHEN ( ( 1 <> 1 ) AND ( 1 <> 2 ) AND ( 1 <> NULL ) ) THEN 'True' ELSE 'Unknown or False' END ;

謂詞有短路特性,即在AND條件中,只要有一個條件為false,整個條件都為false,而1<>1是為false,所以后面的也不需要判斷了,直接返回else部分。即使是1<>null,根據集合論的特性,NULL和實際數據的對比總是返回unknown,所以也是為false。如果你非要用NOT IN ,請確保子查詢永遠不會有NULL返回?;蛘咝枰~外處理去除NULL,比如:

SELECT Barcode FROM dbo.ShipmentItems WHERE ShipmentBarcode = '123654' AND Barcode NOT IN ( SELECT Barcode FROM dbo.ShipmentItems WHERE ShipmentBarcode = '123456' AND Barcode IS NOT NULL ) ;

還有一種方法就是改寫語句,用NOT EXISTS來等價替換:

SELECT i.Barcode FROM dbo.ShipmentItems AS i WHERE i.ShipmentBarcode = '123654' AND NOT EXISTS ( SELECT * FROM dbo.ShipmentItems AS i1 WHERE i1.ShipmentBarcode = '123456' AND i1.Barcode = i.Barcode ); /* Barcode ------------------------------ 1010204 */

另外,基于SARG要求,一般不建議用NOT IN/NOT EXISTS這種反向掃描,避免影響性能。還有一個選擇使用IN/EXISTS的要點,就是多列匹配的問題,在T-SQL中,多列同時匹配要用EXISTS,而單列匹配可以用EXISTS/IN??赡芸梢杂闷渌麑懛▉韺崿FIN的多列匹配,但是一般我個人會選擇使用EXISTS來匹配多列。


原文出自:CSDN博客:黃釗吉的博客

總結

以上是生活随笔為你收集整理的开发随笔——NOT IN vs NOT EXISTS的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。