在王珊、薩師煊的《數據庫系統概論》第五版書中的P108例子比較難理解。
存在量詞
EXISTS謂詞:
帶有EXISTS謂詞的子查詢不返回任何數據,只產生邏輯真值“true”或邏輯假值“false”。
若內層查詢結果非空,則外層的WHERE子句返回真值;
若內層查詢結果爲空,則外層的WHERE子句返回假值。
由EXISTS引出的子查詢,其目標列表達式通常都用* ,因爲帶EXISTS的子查詢只返回真值或假值,給出列名無實際意義。
NOT EXISTS謂詞
若內層查詢結果非空,則外層的WHERE子句返回假值;
若內層查詢結果爲空,則外層的WHERE子句返回真值。
SQL中沒有全稱量詞,可以把帶有全稱量詞的謂詞轉換爲等價的帶有存在量詞的謂詞。
【例3.62】查詢選修了全部課程的學生姓名
SELECT Sname
FROM Student
WHERE NOT EXISTS
( SELECT *
FROM Course
WHERE NOT EXISTS
( SELECT *
FROM SC
WHERE Sno = Student.Sno AND Cno = Course.Cno
)
);
理解這個代碼,可以舉反例。
對於一個學生,如果他有一門課程沒有選,那麼這個學生就不屬於選修了全部課程的學生。
所以要找的學生是這樣一些學生。
課表上的每一門課,如果有課程沒有選,就把他歸類到有課程沒選的學生羣體裏。
而所要找的學生就是不在上面這個羣體裏的學生。
代碼遍歷學生表,對於每一個學生,在課程表中找,當該學生有課程沒選時,內層NOT EXISTS爲true,此時外層NOT EXISTS爲false。只有所有課程都選了,內層才爲false,此時外層就爲true了,表明該學生所有的課都選了。
【例3.63】查詢至少選修了學生201215122選修的全部課程的學生學號。
SELECT DISTINCT Sno
FROM SC SCX
WHERE NOT EXISTS
( SELECT *
FROM SC SCY
WHERE SCY.Sno = '20121522' AND NOT EXISTS
( SELECT *
FROM SC SCZ
WHERE SCZ.Sno = SCX.Sno AND SCZ.Cno = SCY.Cno
)
);
對於每個學生,不在這樣的學生羣體中。
該羣體爲對於學號爲20121522的學生所修的每一門課程,只要有一門課,有個學生沒有選,那麼這個學生就被加到這個羣體裏,意味着第二個NOT EXISTS爲true,此時第一個NOT EXISTS爲false。