国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
專題:SQL之EXISTS 供應(yīng)商和學(xué)生考試 的解說為例

專題:SQLEXISTS

以下面的供應(yīng)商的解說為例:進(jìn)行說明EXISTS用法

(例一).設(shè)供應(yīng)商供應(yīng)零件的關(guān)系模式為SP(Sno,Pno,Qty),

其中Sno表示供應(yīng)商號,Pno表示零件號,Qty表示零件數(shù)量。整個數(shù)據(jù)庫如下表:
Sno Pno Qty
168  r1  3
168  r2  4
168  r3  7
169  r2  1
169  r3  5
170  r4  8
171  r7  5
172  r2  1
172  r7  3
A)請問下面的SQL語句返回值是什么?
Select * from SP SPY where exists (select * from SP SPZ where Sno = ‘168’)
解析:在exists 中的子查詢在這個例子中只返回一個值。因為從子查詢中返回的行數(shù)至少有一行exits返回為true,這使得表中的所有記錄都被顯示了出來。

結(jié)果如下:

168  r1  3
168  r2  4
168  r3  7
169  r2  1
169  r3  5
170  r4  8
171  r7  5
172  r2  1
172  r7  3

B)請問下面的SQL語句返回值是什么?
Select * from SP SPY where exists (select * from SP SPZ where Sno=’168’ and SPZ.Pno=SPY.Pno);
解析:返回與168號供應(yīng)商所提供零件相同編號的情況。

168  r1  3
168  r2  4
168  r3  7
169  r2  1
169  r3  5
172  r2  1

C)若想得到與168號供應(yīng)上所提供零件相同的全部供應(yīng)商的全部產(chǎn)品情況?
解析:Select * from SP where Sno in (select Sno from SPwhere Pno in (select Pno from SP where Sno=’168’));
或者:Select * from SP SPX where exists (select * from SPSPY where SPY.Sno=’168’and exists (select * from SP SPZ where SPZ.Sno=SPX.Sno and SPZ.Pno=SPY.Pno));

SQLEXISTS

 

     exists是用來判斷是否存在的,當(dāng)exists(查詢)中的查詢存在結(jié)果時則返回真,否則返回假。not exists則相反

     它所在的查詢屬于相關(guān)子查詢,即子查詢的查詢條件依賴于外層父查詢的某個屬性值,處理過程一般為:

     取外層查詢的第一個元組,根據(jù)它與內(nèi)層查詢相關(guān)的屬性值處理內(nèi)層查詢,若where子句返回true,則將此元組放入結(jié)果表,然后取下一個元組,重復(fù)這個過程直到全部檢查完為止

     即:exists做為where條件時,是先對where 前的主查詢進(jìn)行查詢,然后用主查詢的結(jié)果一個一個的代入exists的子查詢進(jìn)行判斷,如果為真則輸出當(dāng)前這一條主查詢的結(jié)果,否則不輸出

     建立程序循環(huán)的概念,這是一個動態(tài)的查詢過程。如 FOR循環(huán) 。

     流程為首先取出外層中的第一個元組, 再執(zhí)行內(nèi)層查詢,將外層表的第一元組代入,若內(nèi)層查詢?yōu)檎?,即有結(jié)果時,返回外層表中的第一元 組,接著取出第二元組,執(zhí)行相同的算法。一直到掃描完外層整表

 

for(int i =0; i<EOFout;i++)

{

            for(int j = 0 ; j<EOFin;j++)

 }

 

 

     使用EXISTS,首先檢查主查詢,然后運行子查詢直到它找到第一個匹配項,這就節(jié)省了時間。

     而執(zhí)行IN子查詢時,首先執(zhí)行子查詢,并將獲得的結(jié)果列表存放在一個加了索引的臨時表中。在執(zhí)行子查詢之前,系統(tǒng)先將主查詢掛起,待子查詢執(zhí)行完畢,存放在臨時表中以后再執(zhí)行主查詢。

     因此,使用EXISTS比使用IN通常查詢速度快。

 

(一)解說

例一 A

 Select * fromSP SPY where exists (select * from SP SPZ where Sno = ‘168’);

要將他看成

Select * from SP SPY

where exists (select * from SP SPZ where  SPZ .Sno = ‘168’);

按照流程可知:

先去取外層主查詢相關(guān)表SPY的第一個元組(168  r1  3),

再執(zhí)行內(nèi)查詢,將 SPY的第一個元組(168  r1  3)作為一個已知的限制條件帶入;

下面看內(nèi)查詢:

select * from SP SPZ where  SPZ .Sno = ‘168’;

發(fā)現(xiàn)內(nèi)查詢 只和子查詢相關(guān)表SPZ有關(guān),

而和SPY的第一個元組(168  r1  3  沒有任何關(guān)系,也就是說主查詢對子查詢沒有限制。

  那么此時若內(nèi)層查詢?yōu)檎妫从薪Y(jié)果時,返回外層表中的第一元 組,

通過已知的整個數(shù)據(jù)庫數(shù)據(jù)發(fā)現(xiàn),內(nèi)查詢語句肯定有值,即exists返回true

故將外層表中的第一元 放入結(jié)果表。

 

接著取出第二元組,執(zhí)行相同的算法(由于外循環(huán)對內(nèi)循環(huán)沒有影響,而內(nèi)循環(huán)始終為true,所以第二元組 也肯定放到 結(jié)果表中)。

一直到掃描完外層整表 。(發(fā)現(xiàn) 外層表所有記錄 都放入到了 結(jié)果表中)

 

(二)解說

          例一B

 

Select * from SPSPY where exists (select * from SP SPZ where Sno=’168’ and SPZ.Pno=SPY.Pno);

將之看成

Select * from SPSPY

where exists(select * from SP SPZ

where   SPZ .Sno=’168’

and  SPZ.Pno=SPY.Pno);

 

發(fā)現(xiàn)較之 例一 A 內(nèi)循環(huán)多了一個 限制條件 SPZ.Pno=SPY.Pno,

也就是說 在內(nèi)循環(huán)中  引入了外層主查詢相關(guān)表SPY的零件號Pno 。

SPY的第一個元組(168  r1  3)帶入內(nèi)循環(huán)。

 

select * from SP SPZ where SPZ .Sno =’168’

知內(nèi)表SPZ查詢到三條記錄

168  r1  3
168  r2  4
168  r3  7

從上面知道 SPZ.Pno的值在集合(r1,r2,r3)中

 

SPY的第一個元組(168  r1  3)的SPY.Pno=r1,在SPZ.Pno的集合(r1,r2,r3)中,

然后將外層表中的第一元 放入結(jié)果表。

 

SPY的第二個元組(168  r2  4)的SPY.Pno=r2,在SPZ.Pno的集合(r1,r2,r3)中,

然后將外層表中的第二元 放入結(jié)果表。

 

SPY的第三個元組(168  r3  7)的SPY.Pno=r3,在SPZ.Pno的集合(r1,r2,r3)中,

然后將外層表中的第三元 放入結(jié)果表。

 

SPY的第四個元組(169  r2  1)的SPY.Pno=r3,在SPZ.Pno的集合(r1,r2,r3)中,

然后將外層表中的第四元 放入結(jié)果表。

 

SPY的第五個元組(169  r3  5)的SPY.Pno=r3,在SPZ.Pno的集合(r1,r2,r3)中,

然后將外層表中的第五元 放入結(jié)果表。

 

SPY的第六個元組(170  r4  8)的SPY.Pno=r4,不在SPZ.Pno的集合(r1,r2,r3)中,  外層表中的第六元   丟棄

 

SPY的第七個元組(171  r7  5)的SPY.Pno=r7,不在SPZ.Pno的集合(r1,r2,r3)中,  外層表中的第七元   丟棄。

 

SPY的第八個元組(172  r2  1SPY.Pno=r2,在SPZ.Pno的集合(r1,r2,r3)中,

然后將外層表中的第八元 放入結(jié)果表。

 

SPY的第九個元組(172  r7  3)的SPY.Pno=r7,不在SPZ.Pno的集合(r1,r2,r3)中,  外層表中的第九元   丟棄。

 

(三)解說

例一 C

若想得到與168號供應(yīng)上所提供零件相同的全部供應(yīng)商的全部產(chǎn)品情況?

1>要想知道全部供應(yīng)商的全部產(chǎn)品,必須知道全部供應(yīng)商的供應(yīng)商號。

2>要想知道全部供應(yīng)商號,必須知道 全部供應(yīng)商的零件號

3>要想知道全部的零件號,必須知道 168號供應(yīng)商的全部零件號。

 

解析:

Select * from SP where Sno

 in

    (select Sno from SP where Pno

in

(select Pno from SP where Sno=’168’));

即如下:
Select * from SP SPX where SPX .Sno

in

(select SPY .Sno from SP SPY where SPY .Pno

in

(select SPZ .Pno from SP SPZ where SPZ .Sno=’168’));

然后將外層的限制條件 逐層內(nèi)移,用exists代替in

1>

Select * from SP SPX where exists

 (selectSPY .Sno from SP SPY where SPY.Sno=SPX.Sno

and  SPY.Pno  in

(select SPZ .Pno from SP SPZ where SPZ .Sno=’168’));

2>

Select * from SP SPX where

exists (select SPY .Sno from SP SPY where SPY.Sno=SPX.Sno

and

exists (select SPZ .Pno from SP SPZ where SPZ.Sno=’168’

and  SPZ.Pno=SPY.Pno) );

 

由于第二個exists(即內(nèi)exists)需要第一個exists中的SPY.Pno

所以要將之改成

Select * from SP SPX where

exists (select * from SP SPY where SPY.Sno=SPX.Sno

and

exists (select * from SP SPZ where SPZ .Sno=’168’

and  SPZ.Pno=SPY.Pno)  );

 

3>重新組合后,就如答案所示

Select * from SP SPX where

exists (select * from SP SPY whereSPY.Sno=’168’

and

exists (select * from SP SPZ where

SPZ.Sno=SPX.Sno

and  

SPZ.Pno=SPY.Pno));

 

 

第一個 exists存在的意義就是 168號供應(yīng)商的全部零件號,作為第二個exists的限制條件。

 

(例二)下面是另一個例子

1、查詢選修了全部課程的學(xué)生姓名

 
 

思路一(in

     首先學(xué)生的選課信息存在于SC表中, 要想知道某個學(xué)生是否選修了全部課程,至少我們需要知道一共有幾門課程。

     其次,學(xué)生選修了與否,我們又要掃描SC全表,統(tǒng)計出選修了所有課程的學(xué)生號

     最后在STUDENT表中根據(jù)學(xué)生號打出姓名

 

select Sname fromstudent             

where Sno IN

   (select Sno from SC

group by Sno  //根據(jù)Sno分組,統(tǒng)計每個    

/ /學(xué)生選修了幾門課程。如果等于course

//總數(shù),就是我們要找的Sno

    having count(*) =

             (select count(*) from course )

  )    //統(tǒng)計course中共有幾門課程

 

思路二(EXISTS

解二:
select sname from student where

not exists (select *from course where  

not exists (select * from sc where

sc.cno = course.cno

and sc.sno=student.sno)  )

exists做為where 條件時,是先對where 前的主查詢詢進(jìn)行查詢,然后用主查詢的結(jié)果一個一個的代入exists的查詢進(jìn)行判斷,如果為真則輸出當(dāng)前這一條主查詢的結(jié)果,否則不輸出。

上面這個列子,先查詢出student表的結(jié)果,然后將結(jié)果代入到student.sno然后再查詢出sc表中的結(jié)果,再一條一條的代入,感覺有點像for的嵌套循環(huán),第一輪外循環(huán)中,滿足內(nèi)部的not exists條件的course表中的結(jié)果集被保留,然后再判斷外部的not exists,這次判斷是根據(jù)內(nèi)部Course表中被保留的結(jié)果集的情況,如果結(jié)果集為空,則輸出當(dāng)前這一條S表的結(jié)果集;然后再進(jìn)行第二輪大的循環(huán),即取出student表的第二條結(jié)果代入運算。

以上的sql還可以這樣理解,

最內(nèi)部的

select * from sc where sc.cno = course.cno and sc.sno=student.sno

是查詢出所有已經(jīng)選擇過課程的學(xué)生及相應(yīng)課程,

select * from course where   not exists 則是所有沒有被選擇的課程,

在這個基礎(chǔ)上的 select sname from student where not exists

則是選取所有沒有未選擇課程的學(xué)生,即選擇了所有課程的學(xué)員名稱。

 

 

     引入:將題目換為 查找學(xué)號為 00003 沒有選修的科目  

     思路:

     將已知學(xué)號00003代入

     把每一個科目代入(循環(huán))

     將上述兩個條件組合,一一與SC表中的學(xué)號( 00003 )和科目進(jìn)行比對,找不到匹配的就是00003 沒有選修的科目

 

select Cname from course

where notexists//找不到的組合,提交course

        (select * from SC where course.cno = cno        andsno = ''00003'')  //SC中匹配

 

     換個題目: 查找沒有 沒有選修科目的學(xué)生姓名

     思路:學(xué)號未知 , 科目未知,說明有兩個未知變量。應(yīng)該有兩個EXISTS。

     可以掃描student course共有 s * c 中組合,將這些組合與SC的每一項進(jìn)行匹配,注意s*c組合已經(jīng)包含所有可能。如果全部找到 ,就說明已經(jīng)選修了全部課程。找不到就說明有課程沒選修 。再將沒選修的的提交給上一exists 循環(huán) 。若上一exists 不存在的再提交給外循環(huán)。

 

select Sname from student

     where NOTexists        //

            (select * from course

             whereNOT exists //不存在的提 

//交給course

                     (select* from SC where

                Sno= student.sno                                             andcno = Course.Cno)  // //入兩個未知變量

        )

     回頭看,就是我們第一個引出的題目:

     選修了全部課程的學(xué)生姓名

     選了全部課程的學(xué)生變成找這樣的學(xué)生 :不存在一門課他沒選的,也就是沒有課程他沒有選

     舉一反三,請寫出

     被全部學(xué)生都選的課程

 

select Cname from sc

where cno  in

 (select cno from coure

group by cno//根據(jù)cno分組,統(tǒng)計每個    

/ /課程有幾個學(xué)生選修。如果等于student

//總數(shù),就是我們要找的Sno

       having count(*) = (select count(*) from  student )

)

 

     被全部學(xué)生都不選的課程

 

select Cname from sc

where cno  in

 (select cno from coure

group by cno//根據(jù)cno分組,統(tǒng)計每個    

/ /課程有幾個學(xué)生選修。如果等于student

//總數(shù),就是我們要找的Sno

       having count(*) = 0

)

 

2、查詢至少選修了學(xué)生00002選修的全部課程的學(xué)生號碼

3、 它表示的語義為:不存在這樣的課程y,學(xué)生95002選了,而學(xué)生x沒有選

 

select distinct sno

from sc scx

where

not exists(--------------不存在如下情況

      

select *-------------------課程y,學(xué)生95002選了

       fromsc scy

       wheresno='95002'

 

       and

not exist(-------------------但學(xué)生x 沒有選 課程y

             select *

             from sc scz

             where scz.sno = scx.sno

             and scz.cno=scy.cno))  

 

 

SQL語句嵌套與EXISTS謂詞

首先我們要了解一下SQL語句的執(zhí)行過程。

SELECT
字段
FROM
表名
WHERE
條件表達(dá)式

那它們是按什么順序執(zhí)行呢?分析器會先看語句的第一個詞,當(dāng)它發(fā)現(xiàn)第一個詞是SELECT關(guān)鍵字的時候,它會跳到FROM關(guān)鍵字,然后通過FROM關(guān)鍵字找到表名并把表裝入內(nèi)存。接著是找WHERE關(guān)鍵字,如果找不到則返回到SELECT找字段解析,如果找到WHERE,則分析其中的條件,完成后再回到SELECT分析字段。最后形成一張我們要的虛表。

其它的先不說了,只說WHERE

WHERE
關(guān)鍵字后面的是條件表達(dá)式。如果學(xué)過C語言等編程語言就會知道,條件表達(dá)式計算完成后,會有一個返回值,即非00,非0即為真(true)0即為假(false)。同理WHERE后面的條件也有一個返回值,真或假,來確定接下來執(zhí)不執(zhí)行SELECT。

:
SELECT *
FROM STUDENT
WHERE SNO = '1';

分析器先找到關(guān)鍵字SELECT,然后跳到FROM關(guān)鍵字將STUDENT表導(dǎo)入內(nèi)存,并通過指針p1找到第一條記錄,接著找到WHERE關(guān)鍵字計算它的條件表達(dá)式,如果為真那么把這條記錄裝到一個虛表當(dāng)中,p1再指向下一條記錄。如果為假那么p1直接指向下一條記錄,而不進(jìn)行其它操作。一直檢索完整個表,關(guān)把虛表返回給用戶。

再說EXISTS謂詞,EXISTS謂詞也是條件表達(dá)式的一部分。當(dāng)然它也有一個返回值(truefalse)。

:
SELECT Sname
FROM Student
WHERE EXISTS
(SELECT *
FROM SC
WHERE SC.Sno = Student.Sno AND SC.Cno = '1');

這是一個SQL語句的嵌套使用,但和上面說的SQL語句的執(zhí)行過程也是相同的。嵌套的意思也就是說當(dāng)分析主SQL語句(外面的那個SELECT,我們權(quán)且先這么叫它)WHERE關(guān)鍵字的時候,又進(jìn)入了另一個SQL語句中。那么也就是說,分析器先找到表Student并裝入內(nèi)存,一個指針(例如p1)指向Student表中的第一條記錄。然后進(jìn)入WHERE里分析里面的SQL語句,再把SC表裝入內(nèi)存,另一個指針(例如p2)指向SC表中的第一條記錄,分析WHERE后面的條件表達(dá)式,依次進(jìn)行分析,最后分析出一個虛表2,也就變成

SELECT Sname
FROM Student
WHERE EXISTS
虛表2

如果虛表為空表,EXISTS 虛表2 也就為false,不返回到SELECT,而p1指向下一條記錄。如果虛表2不為空也就是有記錄,那么EXISTS 虛表2 true同,返回到SELECT并把p1指向的記錄添加到主SQL語句的虛表1當(dāng)中。(這也是為什么嵌套的SQL語句SELECT 后面為一般為*的原因,因為它EXISTS返回的只是真或假,字段的名沒有意義,用*就行,當(dāng)然用別的也不會錯。)

注意,這里雖然嵌套的SQL語句分析完了,但主SQL語句只執(zhí)行了一遍,也就是說p1指向Student的第一條記錄,p1還要再指向Student表的下一條記錄并分析,這樣又進(jìn)入了嵌套中的SQL語句,同上面說的一樣分析。當(dāng)p1也到了Student表的結(jié)尾,整個SQL語句結(jié)束。返回虛表1Sname這一列。

嵌套就像:

for(int i = 0,i < n, ++i)
for(int j = 0, j < n, ++j)

 

 

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
chp3-2
數(shù)據(jù)庫系統(tǒng)概論課后習(xí)題答案(王珊、薩師煊)
數(shù)據(jù)查詢2之多表查詢
sql Exists 2個題目
手把手教你 SQL 多表查詢
數(shù)據(jù)庫關(guān)系范式
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服