第8講:復雜查詢
一、子查詢概述
1. 子查詢定義
①出現在where子句中的select語句被稱為子查詢,即在where子句中嵌套一個select-from-where
②子查詢返回一個集合,可以通過與這個集合比較來確定另一個查詢集合
2. 三種類型的子查詢
- (not) in子查詢
- θ some/θ all子查詢
- (not) exists子查詢
3. 帶有子查詢的select語句區分為內層查詢和外層查詢(內層查詢被嵌入到外層查詢中)
①非相關子查詢:內層查詢獨立進行,沒有涉及任何外層查詢相關信息的子查詢
②相關子查詢:內層查詢需要依靠外層查詢的某些參量作為限定條件才能進行
- 外層向內層傳遞的參量需要使用外層的表名或表別名來限定
- 相關子查詢只能由外層向內層傳遞參數,這也稱為變量的作用域規則
【示例】求學過001號課程的學生的姓名:
- select Sname from Student Stud where S# in (select S# from SC where C# = ‘001‘ and S# = Stud.S#);
- 參量S#表示內層查詢的S#必須在Student表中也出現過
4. 子查詢是為了判斷下列條件,它們分別對應了in、θ some/θ all、exists子查詢
(1)集合成員資格:某一元素是否是某一個集合的成員
(2)集合之間的比較:某一個集合是否包含另一個集合等
(3)集合基數的測試:測試集合是否為空
二、(not) in子查詢
1. 基本語法形式:表達式 [not] in (子查詢)
①語義:判斷表達式的值是否在子查詢的結果(一個集合)中
【示例1】列出張三、王三同學的所有信息:
- select * from Student where Sname in (‘張三‘, ‘王三‘); // 該處直接使用了某一子查詢的結果(集合)
【示例2】列出選修了001號課程的學生的學號和姓名:
- selsect S#, Sname from Student where S# in
- 子查詢返回學過001號課程的學生的學號(集合),如果某學號在該集合中,就表示該學生學過001號課程,也就是要找的
【示例3】求既學過001號課程,又學過002號課程的學生的學號:
- select S# from SC where C# = ‘001‘ and S# in (select S# from SC where C# = ‘002‘);
- 子查詢返回學過002號課程的學生的學號(集合),如果某學號在該集合中,就表示該學生學過002號課程
【示例4】列出沒學過李明老師講授課程的學生的姓名:
- select Sname from Student where S# not in (selsect S# from SC, Course C, Teacher T where SC.C# = C.C# and C.T# = T.T# and T.Tname = ‘李明‘);
- 子查詢返回學過李明老師講授課程的學生的學號(集合),如果某學號不在該集合中,就表示該學生沒學過李明老師的課
三、θ some/θ all子查詢
1. 基本語法形式:表達式 θ some/all (子查詢)
①θ是比較運算符,可以為<、>、<=、>=、=、<>
②語義:將表達式的值與子查詢的結果(一個集合)進行比較
- “表達式 θ some (子查詢)”的結果為真:表達式的值至少與子查詢結果(集合)中的某一個值相比較滿足θ關系
- “表達式 θ all (子查詢)”的結果為真:表達式的值與子查詢結果(集合)中的所有值相比較都滿足θ關系
【示例1】找出工資最低的教師的姓名:
- select Tname from Teacher where Salary <= all (select Salary from Teacher);
- 子查詢返回所有教師的工資(集合),當某工資小於等於該集合中的所有工資時,則表示該教師工資最低
【示例2】找出001號課成績不是第一的所有學生的學號:
- select S# from SC where C# = ‘001‘ and Score < some (select Score from SC where C# = ‘001‘);
- 子查詢返回學過001號課的學生的成績(集合),如果某成績小於該集合中的某一個工資時,則表示該學生成績不是第一
【示例3】找出001號課成績最高的所有學生的學號:
- select S# from SC where C# = ‘001‘ and Score >= all (select Score from SC where C# = ‘001‘);
【示例4】找出98030101號學生成績最低的課程號:
- select C# from SC where S# = ‘98030101‘ and Score <= all (select Score from SC where S# = ‘98030101‘);
【示例5】找出張三同學成績最低的課程號(相關子查詢):
- select C# from SC, Student Stud where SC.S# = Stud.S# and Sname = ‘張三‘ and Score <= all (select Score from SC where S# = Stud.S#);
- 涉及到姓名,即涉及到Student表,子查詢返回該學生的所有成績
- 此處相關子查詢中,內層循環需要借助外層循環的Stud來限定S#為張三的S#
四、(not) exists子查詢
1. 基本語法形式:[not] exists (子查詢)
①語義:判斷子查詢的結果(一個集合)中是否存在元組
②註:本子查詢較難理解,應註意轉換題目意思,然後從“不存在...不存在”這一語義進行解題。
【示例1】檢索學過001號教師教的所有課程的所有學生的姓名:
- select Sname from Student where not exists (select * from Course where T# = ‘001‘ and not exists (select * from SC where S# = Student.S# and C# = Course.C#));
- 題目語句的意思等價於“不存在有一門001號教師教的課程該同學沒學過”
【示例2】列出沒學過李明老師講授任何一門課程的所有學生的姓名:
- select Sname from Student where not exists (select * from Course, SC, Teacher where Tname = ‘李明‘ and Course.T# = Teacher.T# and Course.C# = SC.C# and S# = Student.S#);
【示例3】列出至少學過98030101號同學學過所有課程的同學的學號:
- select DISTINCT S# from SC SC1 where not exists (select * from SC SC2 where SC2.S# = ‘98030101‘ and not exists (select * from SC where C# = SC2.C# and S# = SC1.S#));
第8講:復雜查詢