CodeGym /課程 /SQL SELF /FROM 裡面用 subquery

FROM 裡面用 subquery

SQL SELF
等級 14 , 課堂 1
開放

我們再深入一點 rabbit hole,來看看怎麼在 FROM 裡面用 subquery。這是 SQL 工程師超常用的招,因為可以直接「現場」組出很強大的臨時 table,還能像資料庫真的有這個 table 一樣重複用。

想像一下,你要做一份報表,需要計算、分組或過濾資料,但又不想在 server 上建一堆臨時 table。怎麼辦?這時 FROM 裡的 subquery 就超好用。它們可以:

  • 先把資料暫時合併或聚合,給主查詢用。
  • 「現場」組出有結構的資料集。
  • 減少操作次數,讓資料庫不用存太多中間資料。

FROM 裡的 subquery 就像迷你 table,你可以在主查詢裡直接用。這很像在組積木:快、彈性又沒什麼額外負擔 :)

FROM 裡 subquery 的基本用法

FROM 裡用 subquery,就是先寫一個 subquery,讓它變成一個臨時 table(或子 table),然後這個 table 就是整個查詢的一部分。你只要做三個步驟:

  1. FROM 裡用括號寫 subquery。
  2. 給這個 subquery 取個 alias(暱稱)。
  3. 像用一般 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_grademax_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

希望你喜歡這堂課... 下一堂會更有趣喔 :)

留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION