現在你已經準備好進入下一步 —— 在 SQL 裡玩玩 巢狀查詢 了。今天我們會聊聊這到底是什麼、為什麼要用、巢狀查詢有哪些類型,還有它們在現實生活中到底有多實用。
巢狀查詢(或子查詢)就是那種會被放在其他 SQL 查詢裡的 SQL 查詢。有點像俄羅斯娃娃或高麗菜:外面有個主查詢,裡面藏著另一個比較小的查詢。子查詢會先執行,然後它的結果會被外面的主查詢拿來用(有時候主查詢也會被叫做「主要查詢」)。
我們來看個例子:
範例 1:它怎麼運作
我們有一個 students 資料表,裡面有這些資料:
| id | 名字 | 年齡 | 群組_id |
|---|---|---|---|
| 1 | 愛麗絲 | 20 | 1 |
| 2 | 鮑勃 | 22 | 2 |
| 3 | 克拉克 | 21 | 1 |
| 4 | 迪娜 | 23 | 3 |
| 5 | 艾蜜莉亞 | 22 | 2 |
還有一個 groups 資料表,裡面存著群組名稱:
| id | 名稱 |
|---|---|
| 1 | 數學班 |
| 2 | 物理班 |
| 3 | 文學班 |
如果我們想知道有哪些群組裡有學生在讀,可以用巢狀查詢:
SELECT 名稱
FROM groups
WHERE id IN (
SELECT 群組_id
FROM students
WHERE 年齡 > 21
);
這裡發生了什麼?
巢狀查詢:
SELECT 群組_id
FROM students
WHERE 年齡 > 21
這個查詢會選出所有年齡大於 21 歲學生的 群組_id。結果會是一個群組 id 的清單,比如 [2, 3]。
主查詢:
SELECT 名稱
FROM groups
WHERE id IN ([子查詢結果])
這個查詢會用子查詢的結果,回傳 id 是 2 或 3 的群組名稱。
結果:
物理班
文學班
還是看不懂?很正常啦。別擔心,等等我們會慢慢拆解。
先從一個簡單的想法開始 —— SELECT 查詢的結果,其實就是一個 虛擬資料表。 它有欄位、有列,不就是資料表嗎?
既然查詢結果是資料表,那你就可以在 JOIN 或更複雜的語法裡用它,就像用真的資料表一樣。
它沒有名字,這有點麻煩。但欄位運算式也沒名字,我們都會給它們 alias(別名)。虛擬資料表也可以這樣搞。
更多細節下次再說 —— 先不爆雷 :P
巢狀查詢的好處
它們讓複雜的問題變簡單。有時候一個資料表沒辦法給你所有你想要的資訊。子查詢可以把查詢拆成兩步:先拿到中間結果,再用它來拿最終資料。
處理中間結果。巢狀查詢很適合你需要先做點額外運算再處理資料的時候。比如找最小值或算總和。
讓程式碼更好讀。巢狀查詢讓你的 SQL 更有結構,特別是當你面對大資料表和複雜邏輯時。
巢狀查詢的主要類型
巢狀查詢可以用在 SQL 查詢的不同地方。根據你寫在哪裡,可以分成幾種。
- 寫在
SELECT裡的子查詢。子查詢會放在欄位清單裡,用來算 值。這很方便,比如你想在結果裡加一個新欄位。
範例 —— 加一個欄位,顯示學生的最大年齡:
SELECT 名字, 年齡,
(SELECT MAX(年齡) FROM students) AS 最大年齡
FROM students;
結果:
| 名字 | 年齡 | 最大年齡 |
|---|---|---|
| 愛麗絲 | 20 | 23 |
| 鮑勃 | 22 | 23 |
| 克拉克 | 21 | 23 |
| 迪娜 | 23 | 23 |
| 艾蜜莉亞 | 22 | 23 |
- 寫在
FROM裡的子查詢。子查詢會被當成暫時的資料表。如果你要先聚合或轉換資料,這超好用。
範例 —— 算每個群組學生的平均年齡:
SELECT tmp.群組_id, tmp.平均年齡
FROM (
SELECT 群組_id, AVG(年齡) AS 平均年齡
FROM students
GROUP BY 群組_id
) AS tmp -- 給暫時資料表取個別名 tmp
WHERE tmp.平均年齡 > 21;
結果:
| 群組_id | 平均年齡 |
|---|---|
| 2 | 22.0 |
| 3 | 23.0 |
- 寫在
WHERE和HAVING裡的子查詢。子查詢可以當條件來過濾資料列。這很常用來檢查 - 有沒有資料存在,或是比較數值。
範例 —— 找出年齡大於平均年齡的學生:
SELECT 名字, 年齡
FROM students
WHERE 年齡 > (
SELECT AVG(年齡)
FROM students
);
結果:
| 名字 | 年齡 |
|---|---|
| 鮑勃 | 22 |
| 迪娜 | 23 |
| 艾蜜莉亞 | 22 |
用巢狀查詢的優點
彈性更高:巢狀查詢讓你可以處理更複雜的資料結構。
把問題拆步驟:你可以把邏輯拆成子查詢,讓 SQL 更好懂。
隨時處理中間資料:你可以「即時」處理資料,不用在資料庫裡建暫時資料表。
GO TO FULL VERSION