Logo

新人日誌

首頁關於我部落格

新人日誌

Logo

網站會不定期發佈技術筆記、職場心得相關的內容,歡迎關注本站!

網站
首頁關於我部落格
部落格
分類系列文

© 新人日誌. All rights reserved. 2020-present.

本文為「SQL 資料庫新手村」系列第 56 篇

SQL 可讀性:為什麼巢狀查詢讓人想死

最後更新:2026年2月6日資料庫

上一篇我們用子查詢解決了複雜的需求。

功能是做出來了,但你有沒有發現,那個 SQL 看起來很恐怖?

一層包一層,光是要搞清楚哪個括號對應哪個括號,就讓人頭很痛。

這篇來聊聊,為什麼這種寫法會造成問題,以及我們該怎麼思考這件事。

上一篇的巢狀結構

還記得上一篇的完整 SQL 嗎?

SELECT 三年級自然科班級.班級ID
FROM (
    SELECT 授課班級.班級ID, 課程.學生上限
    FROM 授課班級
    LEFT JOIN 課程 ON 授課班級.課程ID = 課程.課程ID
    WHERE 課程.年級 = 3 AND 課程.科目 = '自然'
) AS 三年級自然科班級
LEFT JOIN (
    SELECT 授課班級.班級ID, COUNT(選課.選課ID) AS 學生人數
    FROM 授課班級
    LEFT JOIN 選課 ON 授課班級.班級ID = 選課.班級ID
    GROUP BY 授課班級.班級ID
) AS 班級學生人數
USING (班級ID)
WHERE 學生人數 < 學生上限

看到這坨東西,你大概會想:「天啊,這到底在寫什麼?」

但其實,這個查詢的主結構很簡單。

我們把子查詢的部分先用名字代替:

SELECT 三年級自然科班級.班級ID
FROM 三年級自然科班級
LEFT JOIN 班級學生人數 USING (班級ID)
WHERE 學生人數 < 學生上限

就是把兩個結果合併,然後篩選。

問題是,我們把子查詢塞進 FROM 和 LEFT JOIN 裡面,整個結構就變得很難讀。

巢狀結構的三個問題

難讀:腦袋要同時記住太多東西

當你讀到 FROM 後面,發現是一段很長的子查詢。

你還沒消化完,又讀到 LEFT JOIN 後面,又是另一段子查詢。

你的腦袋要同時記住兩個複雜的東西,然後再理解它們怎麼合併。

這對人類來說太難了。

電腦不會有這個問題,它就是一行一行執行。

但人類讀程式的時候,腦袋的容量是有限的。

難維護:兩個月後還要能看懂

寫程式不是只有「功能能跑」就好。

你寫的東西,未來你自己要看,你的同事也要看。

想像一下,兩個月後你回來看這段程式。

你可能是要修一個 bug,或是要加一個新功能。

結果你打開程式碼,看到這段巢狀結構,你得從頭理解一次。

這幾乎等於重寫。

很多人以為寫程式是一個人的事。

但實際上,寫程式更像是集體創作。

你會跟團隊的夥伴一起寫,你寫的東西別人要能看懂。

就算是你自己,兩個月後的你,其實也算是「另一個人」了。

所以「意圖性」很重要——讓人一眼就看懂你想做什麼。

難改:複製貼上容易漏改

巢狀結構還有另一個問題:不好改。

假設你有兩個地方都用到類似的子查詢,你可能會複製貼上。

結果要改的時候,你要改兩個地方。

更慘的是,你可能改了一邊,忘了改另一邊,造成結果不一致。

這種 bug 很難發現。

用變數的概念來思考

如果你有寫過其他程式語言,你應該知道「變數」這個東西。

x = 10
y = 20
z = x + y

你可以把一個值存進變數,之後用變數的名字來引用它。

變數還有一個好處:你可以把複雜的運算結果存起來,取一個好懂的名字。

月營收 = 計算這個月的營收()
月成本 = 計算這個月的成本()
月利潤 = 月營收 - 月成本

這樣讀起來就很清楚:月利潤等於月營收減掉月成本。

你不用去看「計算這個月的營收」裡面到底做了什麼複雜的運算,你只要知道它的結果叫做「月營收」就好。

回到 SQL,如果我們也能這樣做就好了。

還記得上一篇的兩個子查詢嗎?

第一個子查詢:查出三年級自然科的班級

SELECT 授課班級.班級ID, 課程.學生上限
FROM 授課班級
LEFT JOIN 課程 ON 授課班級.課程ID = 課程.課程ID
WHERE 課程.年級 = 3 AND 課程.科目 = '自然'

第二個子查詢:算出每個班級的學生人數

SELECT 授課班級.班級ID, COUNT(選課.選課ID) AS 學生人數
FROM 授課班級
LEFT JOIN 選課 ON 授課班級.班級ID = 選課.班級ID
GROUP BY 授課班級.班級ID

如果我們能把這兩段子查詢存起來,給它們取個名字:

三年級自然科班級 = 第一個子查詢的結果
班級學生人數 = 第二個子查詢的結果

那主查詢就可以直接用這些名字:

從 三年級自然科班級 LEFT JOIN 班級學生人數 ...

這樣讀起來就清楚多了。

你可以先看主查詢的結構,知道大概在做什麼。

想看細節的時候,再去看各個「變數」是怎麼算出來的。

SQL 裡面有沒有類似的做法呢?

有的,下一篇會介紹。

小結

這篇聊了巢狀查詢的三個問題:

難讀:

你的腦袋要同時記住多個複雜的子查詢,然後再理解它們怎麼組合。

難維護:

寫程式不是只有當下能跑就好,未來你自己和同事都要能看懂。

難改:

複製貼上的子查詢,改的時候容易漏改,造成結果不一致。

下一篇會介紹 SQL 裡面類似「變數」的做法,讓你把子查詢獨立出來,變得好讀好改。

上一篇跨表單查詢:結合 JOIN 與 INTERSECT 的實戰應用
下一篇SQL 可讀性:CTE 語法全面解析
目前還沒有留言,成為第一個留言的人吧!

發表留言

留言將在審核後顯示。

資料庫

目錄

  • 上一篇的巢狀結構
  • 巢狀結構的三個問題
  • 難讀:腦袋要同時記住太多東西
  • 難維護:兩個月後還要能看懂
  • 難改:複製貼上容易漏改
  • 用變數的概念來思考
  • 小結