我們再深入一點 rabbit hole,來看看怎麼在 FROM 裡面用 subquery。這是 SQL 工程師超常用的招,因為可以直接「現場」組出很強大的臨時 table,還能像資料庫真的有這個 table 一樣重複用。
想像一下,你要做一份報表,需要計算、分組或過濾資料,但又不想在 server 上建一堆臨時 table。怎麼辦?這時 FROM 裡的 subquery 就超好用。它們可以:
- 先把資料暫時合併或聚合,給主查詢用。
- 「現場」組出有結構的資料集。
- 減少操作次數,讓資料庫不用存太多中間資料。
FROM 裡的 subquery 就像迷你 table,你可以在主查詢裡直接用。這很像在組積木:快、彈性又沒什麼額外負擔 :)
FROM 裡 subquery 的基本用法
在 FROM 裡用 subquery,就是先寫一個 subquery,讓它變成一個臨時 table(或子 table),然後這個 table 就是整個查詢的一部分。你只要做三個步驟:
- 在
FROM裡用括號寫 subquery。 - 給這個 subquery 取個 alias(暱稱)。
- 像用一般 table 一樣用這個 alias。
語法
SELECT 欄位
FROM (
SELECT 欄位
FROM 表格
WHERE 條件
) AS 暱稱
WHERE 外部_條件;
看起來有點可怕?我們直接來看例子。
例子:學生和平均分數
假設我們有兩個 table:
students(學生資料-名字和 ID):
| student_id | student_name |
|---|---|
| 1 | Alex |
| 2 | Anna |
| 3 | Dan |
grades(學生分數資料):
| grade_id | student_id | grade |
|---|---|---|
| 1 | 1 | 80 |
| 2 | 1 | 85 |
| 3 | 2 | 90 |
| 4 | 3 | 70 |
| 5 | 3 | 75 |
現在任務:拿到學生名單和他們的平均分數。
我們可以先寫一個 subquery 算出每個學生的平均分,再在主查詢裡用它。
SELECT s.student_name, g.avg_grade
FROM (
SELECT student_id, AVG(grade) AS avg_grade
FROM grades
GROUP BY student_id
) AS g
JOIN students AS s ON s.student_id = g.student_id;
結果:
| student_name | avg_grade |
|---|---|
| Alex | 82.5 |
| Anna | 90.0 |
| Dan | 72.5 |
「現場」臨時 table
FROM 裡的 subquery 超適合你要做多層資料處理的時候。比如說,你不只要平均分,還想算每個學生的最高分-全部一個查詢搞定。
SELECT g.student_id, g.avg_grade, g.max_grade
FROM (
SELECT student_id,
AVG(grade) AS avg_grade,
MAX(grade) AS max_grade
FROM grades
GROUP BY student_id
) AS g;
結果:
| student_id | avg_grade | max_grade |
|---|---|---|
| 1 | 82.5 | 85 |
| 2 | 90 | 90 |
| 3 | 72.5 | 75 |
注意,這就像一個完整的臨時 table,有自己的欄位:avg_grade 和 max_grade。
什麼時候最適合用 FROM 裡的 subquery?
要聚合資料時。 如果你想先算平均、總和或最大值,再跟其他 table 合併。
要先過濾資料時。 當你要先過濾資料再跟主 table 合併。
讓複雜查詢變簡單。 把複雜的事分階段做,才不會亂掉。
例子:兩層處理的學生報表
假設我們想找出平均分超過 80 的學生。先用 subquery 算平均分,再在外面過濾。
SELECT s.student_name, g.avg_grade
FROM students AS s
JOIN (
SELECT student_id, AVG(grade) AS avg_grade
FROM grades
GROUP BY student_id
) AS g ON s.student_id = g.student_id
WHERE g.avg_grade > 80;
結果:
| student_name | avg_grade |
|---|---|
| Alex | 82.5 |
| Anna | 90.0 |
使用小提醒與建議
一定要有 alias。 subquery 一定要取 alias(像 AS g),不然 PostgreSQL 會搞不懂怎麼叫這個「臨時 table」。
效能優化。 FROM 裡的 subquery 有時會比 table join 慢,特別是你在 subquery 裡過濾資料時。
索引。 記得你 join、索引和過濾用到的欄位要有 index-這對效能超有感。
進階例子:課程和學生人數
來做個難一點的。假設我們有這個 table:
courses(課程清單):
| course_id | course_name |
|---|---|
| 1 | SQL Basics |
| 2 | Python Basics |
還有 enrollments(學生選課紀錄):
| student_id | course_id |
|---|---|
| 1 | 1 |
| 1 | 2 |
| 2 | 1 |
現在我們想知道每個課程有多少學生選。
SELECT c.course_name, e.students_count
FROM courses AS c
JOIN (
SELECT course_id, COUNT(student_id) AS students_count
FROM enrollments
GROUP BY course_id
) AS e ON c.course_id = e.course_id;
結果:
| course_name | students_count |
|---|---|
| SQL Basics | 2 |
| Python Basics | 1 |
希望你喜歡這堂課... 下一堂會更有趣喔 :)
GO TO FULL VERSION