WHERE 和 HAVING 都用於設定查詢條件,但它們的 執行時機 和 作用對象 有本質區別。掌握這一點,是編寫高效分組查詢的關鍵。
GROUP BY 分組後的結果進行篩選。SELECT SUM(num) AS rmb FROM `order` WHERE id > 10
-- 先找出 id>10 的記錄,再對這些記錄的 num 求和
SELECT reportsto AS manager, COUNT(*) AS reports
FROM employees
GROUP BY reportsto
HAVING COUNT(*) > 4
-- 先按 reportsto 分組,計算每組人數,再篩選人數>4 的組
若將上述 HAVING 改為 WHERE COUNT(*) > 4 會報錯,因為聚合尚未執行,無法在 WHERE 中使用聚合函數。
| 條件類型 | 使用子句 | 說明 |
|---|---|---|
| 對原始記錄欄位篩選(如 id>10、status='active') | WHERE | 分組前過濾,減少參與聚合的資料量,效率高 |
| 對聚合結果篩選(如 COUNT(*)>4、SUM(amount)>10000) | HAVING | 分組後過濾,只能用於聚合函數或 GROUP BY 欄位 |
| 無分組查詢 | WHERE | 無 GROUP BY 時,HAVING 與 WHERE 效果相同,但語意上首選 WHERE |
GROUP BY region 將相同 region 的記錄分為一組,每組返回一行;非分組欄位必須通過聚合函數返回單一值。HAVING 正是為了彌補 WHERE 無法在分組後篩選的缺口而存在。-- 1. 每個地區總人口、總面積
SELECT region, SUM(population), SUM(area)
FROM bbc
GROUP BY region
-- 2. 僅顯示面積超過 1,000,000 的地區
SELECT region, SUM(population), SUM(area)
FROM bbc
GROUP BY region
HAVING SUM(area) > 1000000
-- 此處不能用 WHERE,因表中無單條記錄面積超過 1000000