博文來源(oracle中的exists 和not exists 用法):http://chenshuai365-163-com.iteye.com/blog/1003247
博文來源( in與exists語句的效率問題):http://www.cnblogs.com/iceword/archive/2011/02/15/1955337.html
(一)
exists (sql 返回結果集為真)
not exists (sql 不返回結果集為真)
如下:
表A
ID NAME
1 A1
2 A2
3 A3
表B
ID AID NAME
1 1 B1
2 2 B2
3 2 B3
表A和表B是1對多的關系 A.ID => B.AID
1 SELECT ID,NAME FROM A WHERE EXIST (SELECT * FROM B WHERE A.ID=B.AID) 2 執行結果為 3 1 A1 4 2 A2 5 原因可以按照如下分析 6 SELECT ID,NAME FROM A WHERE EXISTS (SELECT * FROM B WHERE B.AID=1) 7 --->SELECT * FROM B WHERE B.AID=1有值返回真所以有數據 8 9 SELECT ID,NAME FROM A WHERE EXISTS (SELECT * FROM B WHERE B.AID=2) 10 --->SELECT * FROM B WHERE B.AID=2有值返回真所以有數據 11 12 SELECT ID,NAME FROM A WHERE EXISTS (SELECT * FROM B WHERE B.AID=3) 13 --->SELECT * FROM B WHERE B.AID=3無值返回真所以沒有數據 14 15 NOT EXISTS 就是反過來 16 SELECT ID,NAME FROM A WHERE NOT EXIST (SELECT * FROM B WHERE A.ID=B.AID) 17 執行結果為 18 3 A3
(二)SQL中IN,NOT IN,EXISTS,NOT EXISTS的用法和差別:
IN 關鍵字使您得以選擇與列表中的任意一個值匹配的行。確定給定的值是否與子查詢或列表中的值相匹配。 (1)獲得居住在 California、Indiana 或 Maryland 州的所有作者的姓名和州的列表時,就需要下列查詢: SELECT ProductID, ProductName FROM Northwind.dbo.Products WHERE CategoryID = 1 OR CategoryID = 4 OR CategoryID = 5 然而,如果使用 IN,少鍵入一些字符也可以得到同樣的結果: SELECT ProductID, ProductName FROM Northwind.dbo.Products WHERE CategoryID IN (1, 4, 5) IN 關鍵字之後的項目必須用逗號隔開,並且括在括號中。 (2)下列查詢在 titleauthor 表中查找在任一種書中得到的版稅少於 50% 的所有作者的 au_id,然後從 authors 表中選擇 au_id 與titleauthor 查詢結果匹配的所有作者的姓名: SELECT au_lname, au_fname FROM authors WHERE au_id IN (SELECT au_id FROM titleauthor WHERE royaltyper <50) 結果顯示有一些作者屬於少於 50% 的一類。 NOT IN:通過 NOT IN 關鍵字引入的子查詢也返回一列零值或更多值。 以下查詢查找沒有出版過商業書籍的出版商的名稱。 SELECT pub_name FROM publishers WHERE pub_id NOT IN (SELECT pub_id FROM titles WHERE type = 'business') 使用 EXISTS 和 NOT EXISTS 引入的子查詢可用於兩種集合原理的操作:交集與差集。 (1) 兩個集合的交集包含同時屬於兩個原集合的所有元素。 (2)差集包含只屬於兩個集合中的第一個集合的元素。 EXISTS:指定一個子查詢,檢測行的存在。 本示例所示查詢查找由位於以字母 B 開頭的城市中的任一出版商出版的書名: SELECT DISTINCT pub_name FROM publishers WHERE EXISTS (SELECT * FROM titles WHERE pub_id = publishers.pub_id AND type ='business') SELECT distinct pub_name FROM publishers WHERE pub_id IN (SELECT pub_id FROM titles WHERE type = 'business')
兩者的區別: EXISTS:後面可以是整句的查詢語句如:SELECT * FROM titles IN:後面只能是對單列:SELECT pub_id FROM titles NOT EXISTS: 例如,要查找不出版商業書籍的出版商的名稱: SELECT pub_name FROM publishers WHERE NOT EXISTS (SELECT * FROM titles WHERE pub_id = publishers.pub_id AND type = 'business') 下面的查詢查找已經不銷售的書的名稱: SELECT title FROM titles WHERE NOT EXISTS (SELECT title_id FROM sales WHERE title_id = titles.title_id)
(三)In 於 EXISTS 的效率問題
select * from A where id in(select id from B) 以上查詢使用了in語句,in()只執行一次,它查出B表中的所有id字段並緩存起來.之後,檢查A表的id是否與B表中的id相等,如果相等則將A表的記錄加入結果集中,直到遍歷完A表的所有記錄. 它的查詢過程類似於以下過程 List resultSet=[]; Array A=(select * from A); Array B=(select id from B); for(int i=0;i<A.length;i++) { for(int j=0;j<B.length;j++) { if(A[i].id==B[j].id) { resultSet.add(A[i]); break; } } } return resultSet; 可以看出,當B表數據較大時不適合使用in(),因為它會B表數據全部遍歷一次. 如:A表有10000條記錄,B表有1000000條記錄,那麼最多有可能遍歷10000*1000000次,效率很差. 再如:A表有10000條記錄,B表有100條記錄,那麼最多有可能遍歷10000*100次,遍歷次數大大減少,效率大大提升. 結論:in()適合B表比A表數據小的情況 select a.* from A a where exists(select 1 from B b where a.id=b.id) 以上查詢使用了exists語句,exists()會執行A.length次,它並不緩存exists()結果集,因為exists()結果集的內容並不重要,重要的是結果集中是否有記錄,如果有則返回true,沒有則返回false. 它的查詢過程類似於以下過程 List resultSet=[]; Array A=(select * from A) for(int i=0;i<A.length;i++) { if(exists(A[i].id) { //執行select 1 from B b where b.id=a.id是否有記錄返回 resultSet.add(A[i]); } } return resultSet; 當B表比A表數據大時適合使用exists(),因為它沒有那麼遍歷操作,只需要再執行一次查詢就行. 如:A表有10000條記錄,B表有1000000條記錄,那麼exists()會執行10000次去判斷A表中的id是否與B表中的id相等. 如:A表有10000條記錄,B表有100000000條記錄,那麼exists()還是執行10000次,因為它只執行A.length次,可見B表數據越多,越適合exists()發揮效果. 再如:A表有10000條記錄,B表有100條記錄,那麼exists()還是執行10000次,還不如使用in()遍歷10000*100次,因為in()是在內存裡遍歷比較,而exists()需要查詢數據庫,我們都知道查詢數據庫所消耗的性能更高,而內存比較很快. 結論:exists()適合B表比A表數據大的情況 當A表數據與B表數據一樣大時,in與exists效率差不多,可任選一個使用.