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 BY 在 SELECT 之後執行,就可以使用別名:
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 截取
|
參考資料