SQL 執行邏輯順序:
FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT
SELECT * FROM welcome WHERE id > 1; -- 行級過濾
SELECT * FROM welcome HAVING id > 1; -- 把全表當一組,組級過濾(MySQL 允許,但不推薦)
-- 錯誤:WHERE 不能用聚合函數
SELECT user, MAX(salary) FROM users GROUP BY user WHERE MAX(salary) > 10;
-- ERROR 1111 (HY000): Invalid use of group function
-- 正確:HAVING 過濾聚合後結果
SELECT user, MAX(salary) FROM users GROUP BY user HAVING MAX(salary) > 10;
| 場景 | 推薦子句 | 理由 |
|---|---|---|
| 過濾原始列(如 status=1, age>18) | WHERE | 利用索引,早期過濾減少參與分組的行數,性能最優 |
| 過濾聚合結果(如 COUNT(*)>5, SUM(amount)>1000) | HAVING | 聚合函數只能在 HAVING/SELECT/ORDER BY 中使用 |
| 同時存在 | WHERE + HAVING | WHERE 先篩選行 → GROUP BY → HAVING 再篩選組 |
-- 需求:查詢 2023 年下單金額超過 10000 元的用戶
SELECT user_id, SUM(amount) AS total
FROM orders
WHERE YEAR(create_time) = 2023 -- ① 先按年份過濾行(可用索引)
GROUP BY user_id
HAVING SUM(amount) > 10000; -- ② 再按聚合金額過濾組
HAVING total > 10000(別名),標準 SQL 不一定支持,移植性考慮寫全稱 HAVING SUM(amount) > 10000。HAVING name='abc',雖 MySQL 允許但邏輯混淆,應移至 WHERE。WHERE 過濾行,HAVING 過濾組。 能用 WHERE 解決的絕不拖到 HAVING,這不僅是語法規範,更是性能鐵律——越早過濾,掃描行數越少,查詢越快。