SQL中EXISTS的使用

2021-05-12 08:06:37 字數 2566 閱讀 4270

網上有一些關於exists 說明的例子,但都說的不是很詳細.比如對於著名的供貨商資料庫,查詢:找出**所有零件的**商的**商名,對於這個查詢,網上一些關於exists的說明文章都不能講清楚.

我先解釋本文所用的資料庫例子,''供貨商'' 資料庫,共3個表. 供貨商表 s(s#,sname), 貨物表 p(p#,pname), 供貨商-貨物表 sp(s#,p#).  欄位s#,p#分別代表供貨商和貨物的id.

在c.j.date的資料庫系統導論第八版中文版第147頁給出了, exists的比較正規的解釋, "exists( select ... from ...)取真值,當且僅當 select ... from ... 取非空值.在作為相關子查詢的例子中,sql涉及子查詢,因此它包含了一範圍變數的引用,即隱式範圍變數s, 它在外查詢中定義." 

我個人認為,此處所指的外查詢定義的隱式範圍變數s,  可以用另外一種方法來解釋:  將外查詢表的每一行,代入內查詢作為檢驗, 如果內查詢返回的結果取非空值,則exists子句返回true, 這一行行可作為外查詢的結果行, 否則不能作為結果.

至此可以明確,exists(包括 not exists )子句的返回值是乙個bool值. exists內部有乙個子查詢語句(select ... from...), 我將其稱為exist的內查詢語句.其內查詢語句返回乙個結果集. exists子句根據其內查詢語句的結果集空或者非空,返回乙個布林值.

舉一例子說明: 找出**所有零件的**商的**商名

select distinct s.sname

from s

where not exists

(select *

from p

where not exists

(select *

from sp

where sp.s#=s.s#

and sp.p#=p.p#) );

假設資料如下:s s# sname

1 s1

2 s2

p p# pname

1 p1

2 p2

sp s# p#

1 1

1 2

2 1

這個查詢過程如下:

step1:      將s表第一行(1,s1) 作為隱式變數v1, 代入第乙個not exists子句. 由於這個子句巢狀乙個not exists子句, 再將 p表第一行(1,p1) 作為隱式變數v2, 和v1一起代入第二個not exists子句中, 這時第二個not exists的內查詢子句變成

select *

from sp

where sp.s#=1

and sp.p#=1

其返回結果集為s# p#

1 1

這個返回結果集非空,注意not exists子句返回的是exists子句的非,因此 第二個not exists 子句返回false. 因此v2不能加入第乙個not exists子句的內查詢子句返回結果.

同理,將p表第二行(2,p2)作為隱式變數v3, 與v1一起代入第二個not exists子句中,內查詢返回結果集非空(返回 行(1,2) ), 因此v3也不能加入第乙個not exists子句的內查詢返回結果集.

至此, 對於隱式變數v1(也就是s的第一行), p表的每一行都已代入第二個not exists子句中進行檢驗,返回結果是乙個空集, 因此對於第乙個not exists子句,其內查詢子句返回結果為空.因此,第乙個not exists子句返回true.因此, v1(1,s1)加入外查詢的結果集.

step 2:    將s表的第二行(2,s2)作為隱式變數 v4, 代入第乙個 not exists 子句. 將 v4,v2, 一起代入第二個not exists子句. 第二個not exists子句內查詢結果集返回非空(2,1),第二個not exists子句返回false.v2 不能加入第乙個not exists子句的內查詢結果集.

將v4,v3 一起代入第二個not exists子句,  這時第二個not exists子句的內查詢子句變成:

select *from sp

where sp.s#=2

and sp.p#=2

在sp表中,並沒有s#=2 and p#=2 的一行,因此,第二個not exists子句的內查詢子句返回空集,第二個not exists子句返回 true. 因此v3, 可以插入第乙個not exists子查詢結果集.

至此, 對於隱式變數v4(也就是s的第2行), p表的每一行都已代入第二個not exists子句中進行檢驗.第乙個not exists子查詢語句返回結果集為:p# pname

2 p2

非空,因此第乙個not exists子句返回false,v4(2,s2) 不能加入外查詢的結果集.

至此s表的每一行都代入第乙個not exists子句中進行檢驗, 外查詢的返回結果是

sname

s1 查詢結束.

從上述查詢過程來可以得知, 第二個not exists子句的內查詢語句返回的結果集的含義是, 乙個供貨商能否**某種貨物. 第乙個not exists的內查詢語句返回的結果集的含義是, 某乙個供貨商不能**的貨物. 而連起來使用,就是用排除法得到"沒有不能**的貨物的供貨商", 也就是能**所有貨物的供貨商.

SQL中 IN 與 EXISTS的使用

大家在談到sql優化時,都會說到用exists 代替 in 查詢。現在就談談這兩個的用法。in查詢相當於多個or條件的疊加,這個比較好理解,比如下面的查詢 select from user where userid in 1 2,3 等效於 select from user where userid...

SQL中exists的使用方法

exists用於檢查子查詢是否至少會返回一行資料,該子查詢實際上並不返回任何資料,而是返回值true或false 有乙個查詢如下 複製 如下 select c.customerid,companyname from customers c where exists select orderid fr...

SQL中exists的使用方法

有乙個查詢如下 複製 如下 select c.customerid,companyname from customers c where exists select orderid from orders o where o.customerid cu.customerid 這裡面的exists是如...