數據庫作業8:SQL練習5 - SELECT(嵌套查詢EXISTS、集合查詢、基於派生表的查詢)

一、帶有EXISTS謂詞的子查詢

①EXISTS代表存在量詞∃。帶有EXISTS的子查詢不返回任何數據,只產生邏輯真值‘true’或邏輯假值‘false’。
②使用存在量詞EXISTS後,若內層查詢結果非空,則外層的WHERE子句返回真值,否則返回假值。
③與EXISTS謂詞相對的是NOT EXISTS謂詞,使用存在量詞NOT EXISTS後,若內層查詢結果,則外層的WHERE子句返回真值,否則返回假值。
④由EXISTS引出的子查詢,其目標列表達式通常都用*,因爲帶EXISTS的子查詢只返回真值或假值,給出列名無實際意義。
⑤所有帶IN謂詞、比較運算符、ANY和ALL謂詞的子查詢都能用帶EXISTS謂詞的子查詢等價替換。
在這裏插入圖片描述
(本例是相關子查詢)

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

查詢結果:在這裏插入圖片描述
在這裏插入圖片描述

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

查詢結果:在這裏插入圖片描述
在這裏插入圖片描述
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));

從而EXISTS和NOT EXISTS來實現帶全稱量詞的查詢。
在這裏插入圖片描述
本查詢可以用邏輯蘊涵來表達:查詢學號爲x的學生,對所有的課程y,只要201215122學生選修了課程y,則x也選修了y。
形式化表示:用p表示謂詞“學生201215122學生選修了課程y”
用q表示謂詞“學生x選修了課程y”
則上述查詢爲:(∀y)p→q
SQL語言中沒有蘊涵邏輯運算,但是可以利用謂詞演算將一個邏輯蘊涵的謂詞等價轉換爲:p→q ≡ ┐p∨q
該查詢可以轉換爲如下形式:
(∀y)p→q≡ ┐∃y(p∧┐q)意思爲:不存在這樣的課程y,學生201215122選修了y,而學生x沒有選。

SELECT DISTINCT Sno
FROM SC SCX
WHERE NOT EXISTS
      (SELECT*
       FROM SC SCY
	   WHERE SCY.Sno='201215122'AND
	         NOT EXISTS
	         (SELECT*
			 FROM SC SCZ
			 WHERE SCZ.Sno=SCX.Sno AND
			    SCZ.Cno=SCY.Cno));

二、集合查詢

集合操作主要包括並操作UNION交操作INTERSECT差操作EXCEPT
在這裏插入圖片描述

SELECT *
FROM Student
WHERE Sdept='CS'
UNION
SELECT *
FROM Student
WHERE Sage<=19;

查詢結果:在這裏插入圖片描述
使用UNION將多個查詢結果並起來時,系統會自動去掉重複元組。如果要保留重複元組則用UNION ALL操作符
在這裏插入圖片描述

SELECT Sno
FROM SC
WHERE Cno='1'
UNION
SELECT Sno
FROM SC
WHERE Cno='2';

查詢結果:在這裏插入圖片描述
在這裏插入圖片描述

SELECT *
FROM Student
WHERE Sdept='CS'
INTERSECT
SELECT *
FROM Student
WHERE Sage<='19';

查詢結果:在這裏插入圖片描述
(沒有什麼錯是不能出的😁,我第一個SELECT後面寫的*,第二個我就寫成了Sno,然後就出錯了🐷自罰三瓶養樂多👍在這裏插入圖片描述
在這裏插入圖片描述

SELECT Sno
FROM SC
WHERE Cno='1'
INTERSECT
SELECT Sno
FROM SC
WHERE Cno='2';

查詢結果:在這裏插入圖片描述
(注意,這個題就不能SELECT *,否則會沒有查詢結果,因爲上一題查詢的是不同屬性,而這個題查詢的是同一個屬性的不同結果,比如這個查詢時如果不只選擇學號,則會造成課程號和成績不同則沒有查詢結果)
在這裏插入圖片描述

SELECT *
FROM Student
WHERE Sdept='CS'
EXCEPT
SELECT *
FROM Student
WHERE Sage<='19';

查詢結果:在這裏插入圖片描述
(也就是查詢計算機科學系中年齡大於19歲的學生)


三、基於派生表的查詢
子查詢不僅可以出現在WHERE子句中,還可以出現在FROM子句中,這時子查詢生成的臨時派生表成爲主查詢的查詢對象。

在這裏插入圖片描述

/*改寫後的*/
SELECT Sno,Cno
FROM SC,(SELECT Sno,AVG(Grade) FROM SC GROUP BY Sno)
         AS Avg_SC(avg_sno,avg_grade)
WHERE SC.Sno=Avg_sc.avg_sno and SC.Grade>=Avg_sc.avg_grade

/*改寫前的*/
SELECT Sno,Cno
FROM SC x
WHERE Grade>=(SELECT AVG(Grade)
              FROM SC y
			  WHERE y.Sno=x.Sno);

查詢結果都爲 :在這裏插入圖片描述

Emmmm,相比較我更喜歡改寫前的那種(因爲好寫)。
改寫前的意思是:這就是一個嵌套查詢,先查詢SC x的學生,然後在y裏求了這個學生所有選修的平均成績後,在跟該學生的各科成績比較,然後返回符合條件的查詢值。
改寫後的意思是:FROM子句中子查詢會生成一個新表,主查詢將SC表和新生成的派生表再通過某種屬性相連接。

如果子查詢中沒有聚集函數,派生表可以不指定屬性列,子查詢SELECT後面的列名爲其默認屬性。比如下例:
在這裏插入圖片描述

/*改寫後的*/
SELECT Sname
FROM Student,(SELECT Sno FROM SC WHERE Cno='1')AS SC1
WHERE Student.Sno=SC1.Sno;

/*改寫前的*/
SELECT Sname
FROM Student
WHERE EXISTS
      (SELECT*
       FROM SC
	   WHERE Sno=Student.Sno AND Cno='1');

查詢結果都是:在這裏插入圖片描述

改寫前的意思是:查詢Student表裏的學生,在查找SC表這些學生裏Cno是否爲1,是的話返回真值,返回該學生對應的Sname,不是的話查詢下一個元組。
改寫後的意思是:把SC表裏Cno=1的形成一個派生表,在查詢與Student表與SC表裏Sno相等的,返回該學生的Sname。

通過FROM子句生成派生表時,AS關鍵字可以省略,但必須爲派生關係指定一個別名。


SELECT總結:

SELECT語句的一般格式:

SELECT [ALL|DISTINCT] 	<目標列表達式> [別名] [ ,<目標列表達式> [別名]]FROM <表名或視圖名> [別名] [ ,<表名或視圖名> [別名]]|(<SELECT語句>)[AS]<別名>
[WHERE <條件表達式>] 
[GROUP BY <列名1>[HAVING<條件表達式>]] 
[ORDER BY <列名2> [ASC|DESC]];

SELECT查詢:

①單表查詢:選擇表中的若干列;選擇表中的若干元組;ORDER BY子句;聚集函數;GROUP BY子句。
②連接查詢:等值與非等值連接查詢;自身連接;外連接;多表連接。
③嵌套查詢:帶IN謂詞的子查詢;帶有比較運算符的子查詢;帶有ANY或ALL謂詞的子查詢;帶有EXISTS謂詞的子查詢。
④集合查詢:集合操作主要包括並操作UNION交操作INTERSECT差操作EXCEPT
⑤基於派生表的查詢

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章