你真的會玩SQL嗎?系列目錄
此文是繼文章 你真的會玩SQL嗎?三值邏輯 而補充的,那來探討下為什么有人會建議有些地方用EXISTS代替in
EXISTS和IN之間的區別
1.EXISTS只返回TRUE或FALSE,不會返回UNKNOWN。
2.IN當遇到包含NULL的情況,那么就會返回UNKNOWN。
當查詢的列包含NULL時,NOT EXISTS正常返回TRUE或FALSE。
而NOT IN可能返回空集,如下
1:val IN(val1,val2,...,NULL),永遠不會返回FALSE,而是返回TRUE或UNKNOWN。
2:val NOT IN(val1,val2,...,NULL),永遠不會返回TRUE,而是返回NOT TRUE或NOT UNKNOWN。
看個示例:
Test1表
select t.[name] from Test as t
where exists (select t1.orderid from Test1 as t1 where t1.[name]=t.[name])
返回 aaa,ccc,ddd
select t.[name] from Test as t
where t.[name] in (select t1.[] from Test1 as t1)
返回 aaa,ccc,ddd
select t.[name] from Test as t
where not exists (select t1.orderid from Test1 as t1 where t1.[name]=t.[name])
返回 bbb
select t.[name] from Test as t
where t.[name] not in (select t1.[name] from Test1 as t1)
返回空集
練習
以下對就返回哪三值?
答案


用例數據庫文件 你真的會玩SQL嗎?之邏輯查詢處理階段 文末
/*寫一條查詢語句,返回在2007年下過訂單,而在2008年沒有下過訂單的客戶。 涉及的表:Sales.Customers表和Sales.Orders表。用exists 期望的輸出:*/ custid companyname ----------- ---------------------------------------- 21 Customer KIDPX 23 Customer WVFAF 33 Customer FVXPQ 36 Customer LVJSO 43 Customer UISOJ 51 Customer PVDZC 85 Customer ENQZT
參考SQL:

--answer: select custid, companyname from Sales.Customers as C where EXISTS (select * from Sales.Orders as O where O.custid = C.custid and O.orderdate >= '20070101' and O.orderdate < '20080101') and not EXISTS (select * from Sales.Orders as O where O.custid = C.custid and O.orderdate >= '20080101' and O.orderdate < '20090101'); /* 1.先處理外層查詢,從Sales.Customers表別名C中取出一個元組,將元組相關列值custid傳給內層查詢 2.執行第一層內層查詢,Sales.Orders表別名O,應用where子句返回滿足條件O.custid = C.custid和orderdate在2007年至2008年 3.執行第二層內層查詢,Sales.Orders表別名O應用where子句返回滿足條件O.custid = C.custid和orderdate在2008年至2009年的值 4.執行not EXISTS,外查詢根據子查詢返回的結果集得到滿足條件的行 */