SQL 子查詢 EXISTS 和 NOT EXISTS


內容來源於網上:https://blog.csdn.net/qq_27571221/article/details/53090467

 

 

 

將主查詢的數據,放到子查詢中做條件驗證,根據驗證結果(TRUE 或 FALSE)來決定主查詢的數據結果是否得以保留。

下面來三張表的實例

我們先介紹下使用的3個數據表:

student數據表:

sno 學號 sname ssex sage
20161181 Altair 20
20161182 Desmond 18
20161183 Ezio 22
20161184 Christina 19

course數據表:

cno 課程編號 cname 課程名
1 C語言
2 數據結構
3 信號與系統
4 模擬電子技術
5 高數

sc數據表:

sno 學號 cno 課程編號 grade 成績
20161181 1 99
20161182 2 98
20161181 2 97
20161181 3 95
20161184 3 92
20161181 4 90
20161181 5 88
20161183 5 58

EXISTS

EXISTS代表存在量詞∃。帶有EXISTS謂詞的子查詢不返回任何數據,只產生邏輯真值“true”或者邏輯假值“false”。

一個例子1.1:

要求:查詢選修了課程”信號與系統“的同學

SELECT s.Sname FROM student s
WHERE EXISTS  
(SELECT * FROM sc, course c WHERE sc.sno = s.sno AND sc.cno = c.cno AND c.cname = '信號與系統')

 

使用存在量詞EXISTS后,若內層查詢結果為非空,則外層的WHERE子句返回值為真,否則返回值為假。

在本例中,首先分析最內層的語句:

SELECT * FROM sc, course c WHERE sc.sno = s.sno AND sc.cno = c.cno AND c.cname = '信號與系統'
  • 1

本例中的子查詢的查詢條件依賴於外層父查詢的某個屬性值(本例中的是Student的Sno值),這個相關子查詢的處理過程是:

首先取外層查詢中(student)表的第一個元組,根據它與內層查詢相關的屬性值(Sno值)處理內層查詢,若外層的WHERE返回為真,則取外層查詢中該元組的Sname放入結果表;

然后再取(student)表的下一組,重復這一過程,直至外層(Student)表全部檢查完畢。

查詢結果表:

Sname
Altair
Christina

NOT EXISTS

與EXISTS謂詞相對的是NOT EXISTS謂詞。使用存在量詞NOT EXISTS后,若對應查詢結果為空,則外層的WHERE子語句返回值為真值,否則返回假值。

例子2.1:
要求:查詢沒有選修課程”信號與系統“的同學

SELECT s.Sname FROM student s
WHERE NOT EXISTS  
(SELECT * FROM sc, course c WHERE sc.sno = s.sno AND sc.cno = c.cno AND c.cname = '信號與系統')

 

使用NOT EXISTS之后,若內層查詢結果為非空,則對應的NOT EXISTS不成立,所以對應的WHERE語句也不成立。

在例子1.1中李勇同學對應的記錄符合內層的select語句的,所以返回該記錄數據,但是對應的NOT EXISTS不成立,WHERE語句也不成立,表示這不是我們要查詢的數據。

查詢結果表:

Sname
Desmond
Ezio

例子2.2(這是一個用NOT EXISTS表示全稱量詞的例子):

要求:查詢選修了全部課程的學生姓名。

SQL語句:

SELECT Sname  
FROM Student   
WHERE NOT EXISTS  
(SELECT * FROM Course WHERE NOT EXISTS  
     (SELECT * FROM SC WHERE Sno=Student.Sno AND Cno=Course.Cno)  
);  

 

這個算是一個比較復雜的sql語句了,兩個EXISTS和三個WHERE。

這個sql語句可以分為3層,最外層語句,最內層語句,中間層語句。

我們很關心最外層語句,因為結果表中的數據都是最外層的查詢的表中的數據,我們更關心最內層的數據,因為最內層的數據包含了全部的判斷語句,決定了student表中的那一條記錄是我們查詢的記錄。

我們由內而外進行分析:

最外層的student表中的第一條記錄是Altair同學對應的記錄,然后中間層的course表的第一條記錄是數據庫對應的記錄,然后對該數據進行判斷(最內層的WHERE語句),結果返回真,則內層的NOT EXISTS為假,
然后繼續對course表中的下一條記錄進行判斷,返現NOT EXISTS的值也為假,直到遍歷完course表中的所有的數據,內層的NOT EXISTS的值一直都是假,所以中間層的WHERE語句的值也一直都是假。
對應student的Altair記錄,course表中的所有的記錄對應的中間層的返回值為假,所以最外層的NOT EXISTS對應的值為真,最外層的WHERE的值也為真,則Altair對應的記錄符合查詢條件,裝入結果表中。
然后繼續對student表中的下一條記錄進行判斷,直達student表中的所有數據都遍歷完畢。

下面是我自己對這段sql的解讀:

先取一條student記錄,進入中層,再取一條course的記錄,進入內層,此時student的記錄和course的記錄,作為內層判斷的條件,比如此時我取的第一條記錄是Altair,那么我里面的Sql就可以寫成

SELECT * FROM Course WHERE NOT EXISTS  
     (SELECT * FROM SC WHERE Sno = '20161181' AND Cno=Course.Cno) )

 

此處 sno 20161181即Altair的學號,這條sql的意思是選出沒有被Altair選擇的課程,如果不存在,則返回false,再跟最外層的NOT EXISTS關聯,負負得正。每一條循環的意思就是指,篩選出的每一個學生都不存在沒有被他選取的那門課,即選了所有課。

最終查詢結果:

Sname
Altair


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM