CodeGym /課程 /SQL SELF /用法 SELECT 在 SELECT 裡面

用法 SELECT 在 SELECT 裡面

SQL SELF
等級 13, 課堂 1
開放

想像一下你現在是大學的分析師(我們不是在做大學的資料庫嗎,還記得吧?)。你被要求不只是列出學生和他們的成績,還要在表格裡加一欄,顯示該組的最高分,這樣就能輕鬆比較每個人的表現。這要怎麼做?當然就是用 SELECT 裡的子查詢啦!

SELECT 裡的子查詢可以讓你在主查詢執行時直接算出值。這超方便,因為你可以在一個查詢裡組合聚合運算、複雜的篩選,甚至拉進其他資料集合。

SELECT 裡巢狀查詢的基礎

在 SELECT 裡的子查詢就像字面意思一樣:你把一個 SELECT 的結果塞進另一個 SELECT。這樣就能幫每一列結果算出額外的值。

來個簡單例子。假設我們有一張 students 表,結構如下:

student_id name group_id
1 Linda 101
2 Otto 102
3 Anna 101

還有一張 grades 表:

grade_id student_id grade
1 1 5
2 1 4
3 2 3
4 3 5
5 3 4

範例 1:加上組內最高分

任務:列出學生名字、他們的成績,還有該組的最高分,這樣就能看到每個學生和組內最強的差距。

SQL 程式碼:

SELECT
    s.name AS student_name,
    g.grade AS student_grade,
    (
        SELECT MAX(grade) -- 這個查詢只會回傳一個值 
        FROM grades 
        INNER JOIN students ON grades.student_id = students.student_id
        WHERE students.group_id = s.group_id
    ) AS max_group_grade 
FROM 
    students s
INNER JOIN 
    grades g ON s.student_id = g.student_id;

這裡發生了什麼:

  1. 對每個學生,我們拿到他的名字和成績(s.name, g.grade)。
  2. SELECT MAX(grade) — 這是子查詢,會回傳該學生組內的最高分。
  3. 子查詢會對主查詢的每一列執行,並用 WHERE students.group_id = s.group_id 條件,限制只查一個組。

範例 2:組內平均分

想對分析師更有幫助嗎?我們不只加最高分,還加上組內的平均分。

SQL 程式碼:

SELECT
    s.name AS student_name,
    g.grade AS student_grade,
    (
        SELECT AVG(grade) 
        FROM grades 
        INNER JOIN students ON grades.student_id = students.student_id
        WHERE students.group_id = s.group_id
    ) AS avg_group_grade
FROM 
    students s
INNER JOIN 
    grades g ON s.student_id = g.student_id;

現在:

  • 我們用 AVG() 取代 MAX(),來算組內平均分。
  • 這樣就能「即時」分析資料。

限制與建議

SELECT 裡的子查詢很強大,但用的時候要小心:

  1. 效能。 每一列都會執行一次子查詢。如果表很大,SQL 查詢會變慢。比如有 1000 個學生,子查詢就會跑 1000 次!
  2. 索引。 要讓這種查詢快,記得把參與 WHERE 條件的欄位建好索引。
  3. 可讀性。 盡量不要巢狀太多。如果子查詢太複雜,可以考慮搬到 FROM 或用暫存表。

使用範例

我們再來看幾個有趣的案例。

範例 3:每個學生的課程數

列出一個表,顯示每個學生選了幾門課。enrollments 表用 student_id 跟學生連結:

student_id course_id
1 201
1 202
2 201
3 203

SQL 程式碼:

SELECT
    s.name AS student_name,
    (
        SELECT COUNT(*) 
        FROM enrollments
        WHERE enrollments.student_id = s.student_id
    ) AS course_count
FROM 
    students s;

這裡子查詢會算出 enrollments 表裡每個學生的紀錄數。

範例 4:每個學生的「優秀生」標記

來顯示學生是不是優秀生。假設標準是:所有成績都是 5 才算優秀生。

SQL 程式碼:

SELECT
    s.name AS student_name,
    (
        SELECT CASE 
            WHEN MIN(g.grade) = 5 THEN '優秀生'
            ELSE '不是優秀生'
        END
        FROM grades g
        WHERE g.student_id = s.student_id
    ) AS status
FROM 
    students s;

這裡用巢狀 CASE,只有 全部 成績都是 5 的學生才會被標成「優秀生」。

優化 SELECT 裡的子查詢

我們剛剛提過效能可能會有問題。這裡有幾個小技巧可以幫你優化:

  1. 用索引。 如果子查詢有篩選,記得相關欄位要有索引。
  2. 快取結果。 有時候可以把子查詢搬到 VIEW 或暫存表。
  3. 少巢狀。 能簡單就不要複雜,巢狀太多會很難維護。

SELECT 裡的子查詢讓你可以做很多計算和資料分析。雖然有時會吃資源,但只要優化好,SQL 就會變得超靈活又強大。多多嘗試,找到最適合你的查詢寫法吧!

2
任務
SQL SELF, 等級 13, 課堂 1
上鎖
計算每位學生的課程數量
計算每位學生的課程數量
2
任務
SQL SELF, 等級 13, 課堂 1
上鎖
輸出學生的平均成績
輸出學生的平均成績
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION