文章目錄
`MySQL`對嵌套查詢的處理過程是從內層向外層處理,即先處理最內層的子查詢,然後把查詢的結果用於其外查詢的查詢條件,再層層向外求解,最後得出查詢結果。 |
3.子查詢和連接的關係。
一般情況下,包含子查詢的查詢語句可以寫成連接查詢的方式。因此,通過子查詢也可以實現多表之間的查詢。在有些方面,多表連接的性能要優於子查詢,原因是連接不需要查詢優化器執行排序等額外的操作。 |
4.子查詢中的常見運算。
子查詢中可能包括in、not in、any、all、exists、not exists
等邏輯運算符,也可以包含比較運算符,如“=”、“!=”、“>”
和“<”
等。
5.子查詢的類型。
根據子查詢的結果又可以將MySQL
子查詢分爲4種類型。
- 返回一個表的子查詢是表子查詢。
- 返回帶有一個或多個值的一行的子查詢是行子查詢。
- 返回一行或多行,但每行上只有一個值的是列子查詢
- 只返回一個值的是標量子查詢。從定義上講,每個標量子查詢都是一個列子查詢和行子查詢。
6.使用子查詢時應該注意如下的事項。
- 子查詢需要用括號括起來。子查詢中也可以再包含子查詢,嵌套可以多至32層。
- 當需要返回一個值或一個值列表時,可以利用子查詢代替一個表達式。也可以利用子查詢返回含有多個列的結果集替代表或連接操作相同的功能。
- 子查詢不能夠檢索數據類型爲
varchar(max)
、nvarchar(max)
和varbinary(max)
的列。 - 子查詢使用
order by
時,只能在外層使用,不能在內層使用。
二、利用子查詢做表達式
在MySQL
語句中,可以把子查詢的結果當成一個普通的表達式來看待,用在其外查詢的選擇條件中。此時子查詢必須返回一個值或單個列值列表,此時的子查詢可以替換where
子句中包含in關鍵字的表達式。
查詢學號爲18125121107的學生的入學成績、所有學生的平均入學成績及該學生成績與所有學生的平均入學成績的差。 |
分析:利用子查詢求學生的平均入學成績,作爲select語句的輸出項表達式。 |
mysql>select studentno,sname,entrance,
-> (select avg(entrance) from student ) 平均成績,
-> entrance - (select avg(entrance) from student ) 分差
-> from student
-> where studentno='18125121107';
三、利用子查詢生成派生表
select
的數據源由from
子句指定,from
子句可以指定單個表或者多個表,還可以查詢來自視圖、臨時表或結果集的數據源。即可以利用子查詢可以生成一個派生表,用於替代from
子句中的數據源表,派生表可以定義一個別名,即子查詢的結果集可以作爲外層查詢的源表。實際上是在from
子句中使用子查詢作爲派生表數據源。
查詢期末成績高於85分、總評成績高於90分的學生的學號、課程號和總評成績。 |
分析:利用子查詢過濾出期末成績高於85分的結果集,以TT命名,然後再對結果集TT中的數據進行查詢。 |
mysql> select TT.studentno 學號 ,TT.courseno 課程號 ,
-> TT.final*0.8+TT.daily*0.2 總評
-> from (select * from score where final>85) as TT
-> where TT.final*0.8+TT.daily*0.2>90;
四、where子句中的子查詢
where
語句中的子查詢實際上是將子查詢的結果作爲該語句條件中的一部分,然後利用這個條件過濾本層查詢的數據。
1.帶比較運算符的子查詢。
子查詢可以作爲動態表達式,該表達式可以隨着外層查詢的每一行的變化而變化。使得動態執行的子查詢與外部查詢有一個非常有效的連接,從而將複雜的查詢分解爲多個簡單而相互關聯的查詢。查詢可以使用比較運算符。這些比較運算符包括=、!=、>、>=、<、<=
等。比較運算符在子查詢時使用的非常廣泛。
創建關聯子查詢時,外部查詢有多少行,子查詢就執行多少次。
查詢期末成績比選修該課程平均期末成績低的學生的學號、課程號和期末成績。 |
分析:在本例中,對score表採用別名形式,一個表就相當於2個表。子查詢執行時使用的a.courseno相當於一個常量。在別名爲b的表中根據分組計算平均分。然後與外層查詢的值進行比較。該過程很費時間。 |
mysql> select studentno,courseno,final
-> from score as a
-> where final < (select avg(final)
-> from score as b where a.courseno=b.courseno
-> group by courseno );
2.帶in關鍵字的子查詢 。
當子查詢返回的結果列包含一個值時,利用比較運算符就適用查詢要求。假如一個子查詢返回的結果集是值的列表,這時比較運算符就可以用in
運算符代替。
in
運算符可以檢測結果集中是否存在某個特定的值,如果檢測成功就執行外部的查詢。not in
的作用與in剛好相反。
獲取期末成績中含有高於93分的學生的學號、姓名、電話和Email。 |
分析:利用操作符in可以允許指定一個表達式(或常量)集合,可以利用select語句的子查詢輸出表達式(或常量)集合。 |
mysql> select studentno,sname,phone,Email
-> from student where studentno in ( select studentno
-> from score where final>93);
3.帶exists關鍵字的子查詢。
使用exists
關鍵字時,內層查詢語句不返回查詢的記錄。而是返回一個真假值。如果內層查詢語句查詢到滿足條件的記錄,就返回一個真值(true
),否則,將返回一個假值(false
)。當返回的值爲true
時,外層查詢語句將進行查詢;當返回的爲false
時,外層查詢語句不進行查詢或者查詢不出任何記錄。
not exists
與 exists
的工作方式類似,即當not exists
與exists
剛好相反,使用not exists
關鍵字時,當返回的值是true
時,外層查詢語句不執行查詢;當返回值是false
時,外層查詢語句將執行查詢。
查詢student表中是否存在2001年12月12日以後出生的學生,如果存在,輸出學生的學號、姓名、生日和電話。 |
分析:只要存在一行數據符合條件,則where條件就返回TURE,於是輸出所有行。 |
mysql> select studentno,sname,birthdate,phone
-> from student
-> where exists (select * from student
-> where birthdate < '2001-12-12');
4.對比較運算進行限制的子查詢。
all、some
和any
運算都是對比較運算的進一步限制。all
指定表達式要與子查詢結果集中的每個值都進行比較,當表達式與每個值都滿足比較的關係時,才返回true
,否則返回false
。
some
或any
是同義詞,表示表達式只要與子查詢結果集中的某個值滿足比較的關係時,就返回true
,否則返回false
。
查找score表中所有比c05109課程期末成績都高的學號、姓名、電話和期末成績。 |
分析:本題輸出項是學號、姓名、電話和期末成績,分別存在於student表和 score表,因此外層查詢先做一個內連接。在此基礎上,從外層查詢數據源中找出每一個期末成績final的值,讓該值分別與子查詢中的c05109課程的每一個值進行比較,當該外層final值比內層的每一個c05109課程成績都高時,即爲查詢結果集中的一行記錄。以此類推,即可得到本題的結果集。 |
mysql> select student.studentno,sname, phone,final
-> from score inner join student
-> on score.studentno= student.studentno
-> where final >all
-> (select final from score where courseno= 'c05109');
五、利用子查詢插入、更新與刪除數據
1.利用子查詢修改表數據。
就是利用一個嵌套在insert、update
或delete
語句的子查詢成批的添加、更新和刪除表中的數據。
2.利用子查詢插入紀錄。
insert
語句中的 select
子查詢可用於將一個或多個其他的表或視圖的值添加到表中。使用 select
子查詢可同時插入多行。
將student表中2001年以後出生的學生記錄添加到student02表中。 |
分析:子查詢的選擇列表必須與 insert 語句列的列表匹配。如果insert 語句沒有指定列的列表,則選擇列表必須與正向其插入的表或視圖的列匹配且順序一致。 |
mysql> insert into mysqltest.student02
-> (select * from student
-> where birthdate>='2001-12-31');
3.利用子查詢更新數據。
update
語句中的select
子查詢可用於將一個或多個其他的表或視圖的值進行更新。使用 select
子查詢可同時更新多行數據。實際上是通過將子查詢的結果作爲更新條件表達式中的一部分。
將student表中入學成績低於800的所有學生的期末成績增加5%。 |
分析:利用update成批修改表數據,可以在where子句的利用子查詢實現。 同樣在delete語句中利用子查詢可以刪除符合條件的數據行。實際上是通過將子查詢的結果作爲刪除條件表達式中的一部分。 |
mysql> update score
-> set final= final*1.05
-> where studentno in
->(select studentno
->from student
->where entrance <800);