- LAMP網站開發黃金組合Linux+Apache+MySQL+PHP
- 楊明華等編著
- 2779字
- 2018-12-29 19:23:39
4.6 深入SQL查詢語言
上一節介紹了各種簡單的查詢子句,這些查詢都是對一個表進行操作。在本節中會進一步講解比較復雜的SQL查詢語句,主要涉及集合查詢、多表查詢和嵌套查詢。
4.6.1 集合查詢
SQL通常會包含一些集合運算,一般都支持并(UNION)運算,有些SQL版本還有交(INTERSECTION)或差(MINUS)集合運算。SELECT語句查詢的結果是元組的集合,多個SELECT語句的結果可以進行集合操作。但是只有查詢結果互相兼容,才能進行集合運算,即參與運算的查詢結果必須具有相同的列數,并且對應列的屬性域相同。
例如查詢選修課程C001的以及年齡小于22的學生的學號,SQL語句可以如下表達:
SELECT SNO FROM STUDENTS WHERE SAGE<22 UNION SELECT SNO FROM SC WHERE CNO='C001';
★ 說明 ★
使用UNION運算將多個查詢結果合并起來時,系統會自動去掉重復元組。
標準的SQL中沒有直接提供集合交運算和差運算,如果讀者使用的DBMS支持這些運算,可以參考DBMS廠商提供的參考手冊。
4.6.2 連接查詢
連接查詢也叫多表查詢,通過連接運算符可以實現多個表查詢。連接是關系數據庫模型的主要特點,也是它區別于其他類型數據庫管理系統的一個標志。
在關系數據庫管理系統中,表建立時各數據之間的關系不必確定,常把一個實體的所有信息存放在一個表中。當檢索數據時,通過連接操作查詢出存放在多個表中的不同實體的信息。連接操作給用戶帶來很大的靈活性,他們可以在任何時候增加新的數據類型。為不同實體創建新的表,爾后通過連接進行查詢。
連接查詢包括等值和非等值連接查詢、自身連接查詢、外連接查詢和復合條件連接查詢。
1.等值和非等值連接查詢
連接查詢中用來連接兩個表的條件稱為連接條件或連接謂詞,其格式為:
[<表名1>.]<列名1><比較運算符>[<表名2>.]<列名2>其中比較運算符有:“=、>、<、>=、<=、!=”。比較運算符為“=”時,稱為等值連接,其他的稱為非等值連接。連接條件中的列名所指定的字段值必須是可比的,但不一定要求是相同的。
例如要查詢學生以及學生選課的信息,需要查詢學生表(STUDENTS)和學生選課表(SC) 2個表。這兩個表是通過SNO字段相關的。使用等值連接的SQL語句可以如下表達:
SELECT STUDENTS.*,SC.* FROM STUDENTS,SC WHERE STUDENTS.SNO=SC.SNO;
2.自身連接查詢
連接操作不僅可以用于兩個表之間,也可以是一個表與其自己進行連接,稱為自身連接查詢。當一個表所代表的實體之間有關系時,往往可以用到自身連接查詢。例如,前面代表課程的表COURSE,如果課程之間有“先修”關系,則可添加一個字段CPRE,數據模式為COURCE(CNO,CNAME,CCRDIT,CPRE),該字段的值表示某課程先修課程的編號CNO。假設有一COURCE表實例,如表4-9所示,CPRE字段值和CNO字段是可比的。
表4-9 COURCE表

例如要查詢各課程的間接先修課程,實現時為了清楚,可以為COURCE表起兩個別名,假設為CR1和CR2。這樣一來實現該查詢使用的自身連接查詢語句如下:
SELECT CR1.CNO,CR2.CPRE FROM COURCE CR1,COURCE CR2 WHERE CR1.CPRE=CR2.CNO;
實現結果如表4-10所示。
表4-10 查詢結果

3.外連接查詢
在普通的連接操作中,只有滿足連接條件的記錄才能作為結果輸出,在前面講解等值和非等值連接時的例子中,如果有學生沒有選課則選課表(SC)中就沒有對應的該學生學號,那么最后得到的結果中也沒有該學生的其他信息(即STUDENTS表中的信息)。但實際使用時,也許需要以顯示所有學生信息為要求,如果沒有選課,可以在選課信息中設置為空值。這里就用到了外連接查詢。上面的需求可以用如下SQL實現:
SELECT STUDENTS.SNO,SNAME,SSEX,SDEPT,CNO,GRADE FROM STUDENTS,SC WHERE STUDENTS.SNO=SC.SNO(*);
外連接的表示方法為,在連接謂詞的某一邊加上符號*。外連接類似于給添加*的表添加了一個“任意匹配”行,該行記錄能夠和另一邊的表中所有沒有符合連接條件的記錄匹配。這樣的結果是,即使選課表SC中沒有某學生的選課記錄,也可以獲得該學生的STUDENTS表的記錄,但是其SC表中的信息字段都為空。
4.復合連接查詢
上面介紹的連接查詢都是只有一個WHERE子句查詢條件的,實際上WHERE子句中可以有多個連接條件,這樣的查詢稱為復合條件查詢。多個條件使用“AND”關鍵詞連接即可,在這里就不再舉例說明。
4.6.3 嵌套查詢
在SELECT查詢語句里可以嵌入SELECT查詢語句,稱為嵌套查詢。有些書上將內嵌的SELECT語句稱為子查詢,子查詢形成的結果又成為父查詢的條件。SQL語言允許多層嵌套查詢,即一個子查詢中還可以有其他子查詢。子查詢操作的數據表可以是父查詢不操作的數據表。子查詢中不能有ORDER BY子句,ORDER BY子句只能對最終查詢結果排序。
嵌套查詢的求解方法是由里向外處理。即每個子查詢在上一級查詢處理之前求解,子查詢的結果用于建立其父查詢的查找條件。下面通過例子來說明。
例如要查詢選擇課程C002的所有學生的名字和系別,SQL語句如下:
SELECT SNAME,SDEPT FROM STUDENTS WHERE SNO IN SELECT SNO FROM SC WHERE CNO='C002';
本例中,下層SELECT SNO FROM SC WHERE CNO=’C002’查詢子句是嵌套在上層查詢SELECT SNAME,SDEPT FROM STUDENTS WHERE SNO IN的查詢條件中的。下層查詢子句稱為子查詢,上層查詢稱為父查詢。
嵌套查詢可以用多個簡單的查詢構成復雜的查詢。嵌套查詢根據查詢條件的不同具體分為以下四種。
1.帶有IN的子查詢
子查詢結果一般都是一個集合,所以上層查詢條件中使用IN的情況最多。例如要查詢選修了課程名為C++的學生的姓名和系別,SQL語句如下:
SELECT SNAME,SDEPT FROM STUDENTS WHERE SNO IN (SELECT SNO FROM SC WHERE CNO IN (SELECT CNO FROM COURSE WHERE CNAME='C++'));
本例中使用了三層嵌套,最底層的查詢子句用來查詢課程C++的課程序號,第二層的查詢子句根據課程序號查詢選修該課程的學生的學號,最上層的查詢根據學號完成查詢學生姓名和系別的任務。
從例子中可以看出,查詢設計多個表時,用嵌套查詢逐步求解,層次清晰,容易理解,具有結構化程序設計的優點。
2.帶有比較運算符的子查詢
帶有比較運算符的子查詢是指父查詢與子查詢之間用比較運算符進行連接。當用戶能確切知道子查詢返回的是單值時,可以用>,<,=,>=,<=,!=或<>等比較運算符。
例如要查詢和王雪同學在同一個系的學生的姓名和年齡,由子查詢獲得王雪的系別,該子查詢結果必定為一個值,所以在這里可以用“=”,SQL語句如下:
SELECT SNAME,SAGE FROM STUDENTS WHERE SDEPT= (SELECT SDEPT FROM STUDENTS WHERE SNAME='王雪');
3.帶有ANY或ALL的子查詢
使用ANY或ALL謂詞時則必須同時使用比較運算符。具體的語義如下:
● >ANY:大于子查詢結果中的某個值
● >ALL:大于子查詢結果中的所有值
● <ANY:小于子查詢結果中的某個值
● <ALL:小于子查詢結果中的所有值
● >=ANY:大于等于子查詢結果中的某個值
● >=ALL:大干等于子查詢結果中的所有值
● <=ANY:小于等于子查詢結果中的某個值
● <=ALL:小于等于子查詢結果中的所有值
● =ANY:等于子查詢結果中的某個值
● =ALL:等于子查詢結果中的所有值(沒有實際意義)
● !=(或<>=ANY:不等于子查詢結果中的某個值
● !=(或<>)ALL:不等于子查詢結果中任何一個值
例如要查詢數學系中比英語系中某個學生年齡小的學生的名字和年齡,SQL語句如下:
SELECT SNAME,SAGE FROM STUDENTS WHERE SAGE<ANY (SELECT SAGE FROM STUDENTS WHERE SDEPT='English') AND SDEPT='Maths';
★ 注意 ★
最后一行的AND是父查詢的條件。
4.帶有EXISTS的子查詢
EXISTS代表存在量詞?。帶有EXISTS的子查詢不返回任何數據,只產生邏輯真值“true”或邏輯假值“false”。
在講解這種子查詢之前,先介紹兩個概念:不相關子查詢和相關子查詢。在之前的子查詢例子中可以看出,各子查詢都只執行一次查詢操作,其結果集合用于父查詢。子查詢的查詢條件不依賴于父查詢,這類子查詢稱為不相關子查詢。而在帶有EXISTS的子查詢中,查詢條件依賴于父查詢,這類子查詢就稱為相關子查詢。
例如,查詢選修了課程號為C001的課程的學生姓名和系別,SQL語句如下:
SELECT SNAME,SDEPT FROM Student WHERE EXISTS (SELECT * FROM SC WHERE SNO=STUDENTS.SNO AND CNO='C001');
使用存在量詞EXISTS后,若內層查詢結果非空,則外層的WHERE子句返回真值,否則返回假值。
由EXISTS引出的子查詢,其目標列表達式通常都用“*”,因為帶EXISTS的子查詢只返回真值或假值,給出列名無實際意義。
在本例中可以看到子查詢是依賴于父查詢中的某個屬性值(STUDENTS.SNO),求解相關子查詢不能像求解不相關子查詢那樣,一次將子查詢求解出來,然后求解父查詢。內層查詢由于與外層查詢有關,因此必須反復求值。相關子查詢的一般處理過程是:
首先取外層查詢中(STUDENTS)表的第1個元組,根據它與內層查詢相關的屬性值(SNO值)處理內層查詢,若WHERE子句返回值為真,則取此元組放入結果表;然后再取(STUDENTS)表的下一個元組;重復這一過程,直至外層(STUDENTS)表全部檢查完為止。
與EXISTS謂詞相對應的是NOT EXISTS謂詞。使用存在量詞NOT EXISTS后,若內層查詢結果為空,則外層的WHERE子句返回真值,否則返回假值。