Contents

SQL好文分享 - 十步完全理解 SQL

SQL 是一種宣告式語言(Declarative Language),你告訴資料庫「你要什麼結果」,而不是「怎麼取得」。這種設計造成一個常見的困惑:SQL 的語法書寫順序與實際執行順序不同

SQL 語法順序 vs 執行順序

我們寫 SQL 的順序:

1
SELECT   FROM   WHERE   GROUP BY   HAVING   ORDER BY   LIMIT

但資料庫實際執行的順序:

1
FROM → JOIN → WHERE → GROUP BY → HAVING → SELECT → DISTINCT → ORDER BY → LIMIT

為什麼 WHERE 不能用 SELECT 定義的別名?

這是最常讓初學者困惑的問題:

1
2
3
4
-- 這樣寫會報錯!
SELECT salary * 1.1 AS adjusted_salary
FROM employees
WHERE adjusted_salary > 50000  -- 錯誤:找不到 adjusted_salary

原因很簡單:WHERE 的執行順序在 SELECT 之前。當資料庫處理 WHERE 時,SELECT 中定義的別名(adjusted_salary)還不存在,自然找不到。

正確做法是重複計算式,或用子查詢包一層:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
-- 方法一:重複寫計算式
SELECT salary * 1.1 AS adjusted_salary
FROM employees
WHERE salary * 1.1 > 50000;

-- 方法二:用子查詢
SELECT adjusted_salary
FROM (
    SELECT salary * 1.1 AS adjusted_salary
    FROM employees
) AS subquery
WHERE adjusted_salary > 50000;

-- 方法三:用 HAVING(但只適用於聚合後的過濾)

完整的 SQL 執行順序

以一個複雜查詢為例:

1
2
3
4
5
6
7
8
SELECT DISTINCT d.department_name, COUNT(e.id) AS employee_count
FROM employees e
JOIN departments d ON e.department_id = d.id
WHERE e.status = 'active'
GROUP BY d.department_name
HAVING COUNT(e.id) > 5
ORDER BY employee_count DESC
LIMIT 10;

執行步驟依序為:

步驟 子句 說明
1 FROM employees e 載入 employees 資料表
2 JOIN departments d ON ... 與 departments 表合併
3 WHERE e.status = 'active' 過濾掉非 active 員工
4 GROUP BY d.department_name 依部門分組
5 HAVING COUNT(e.id) > 5 過濾掉員工數 ≤ 5 的部門
6 SELECT DISTINCT ... 選取欄位並去除重複
7 ORDER BY employee_count DESC 排序(此時 alias 已存在)
8 LIMIT 10 只取前 10 筆

WHERE 與 HAVING 的差異

理解執行順序後,就能清楚區分 WHERE 和 HAVING:

1
2
3
4
5
6
-- WHERE 在 GROUP BY 之前執行,過濾原始資料列
SELECT department_id, COUNT(*) AS count
FROM employees
WHERE salary > 30000      -- 先過濾薪水 > 30000 的員工
GROUP BY department_id
HAVING COUNT(*) > 3;      -- 再過濾部門員工數 > 3 的部門
  • WHERE:過濾「原始資料列」,不能用聚合函式(SUM、COUNT 等)
  • HAVING:過濾「分組後的結果」,可以用聚合函式

ORDER BY 可以用 SELECT 的別名

既然 ORDER BYSELECT 之後執行,就可以使用別名:

1
2
3
SELECT salary * 1.1 AS adjusted_salary
FROM employees
ORDER BY adjusted_salary DESC;  -- 可以使用別名!

實用記憶口訣

1
2
3
From 哪裡來 → Join 合哪些表 → Where 篩選列 →
Group 分組 → Having 篩選組 → Select 選欄位 →
Distinct 去重 → Order 排序 → Limit 截取

參考資料