我們再來複習一下 SQL 裡操作的執行順序,還有 WHERE 跟 HAVING 到底能做什麼、不能做什麼。這很重要,因為後面很多 SQL 查詢的細節都靠這個觀念。你一定要很熟才行啦。
那到底 WHERE 跟 HAVING 有什麼不一樣?什麼時候該用哪一個?它們又有什麼關聯?搞懂這些你才不會在查詢邏輯裡迷路,也能更有效率地過濾資料。來,我們把 WHERE 跟 HAVING 的知識整理一下。
什麼是 WHERE?
WHERE 就是用來在 群組前 或做聚合函數前,先過濾資料列的條件。也就是說,先從資料表裡挑出符合條件的列,剩下的資料才會被拿去做群組。
👉 想像你在市場挑水果。WHERE 就像你先把爛掉的蘋果挑掉,還沒開始按照大小或顏色分類前就先過濾一遍。
範例:
SELECT *
FROM students
WHERE age > 18;
這個查詢會先選出所有年齡大於 18 歲的學生,在做其他操作之前。
什麼是 HAVING?
HAVING 是在資料 群組之後(GROUP BY)才會用到的過濾條件。它可以讓你針對已經分好組的資料再加條件,比如只留下平均分數超過 80 分的學生群組。
👉 再拿蘋果舉例。HAVING 就是你已經把蘋果分好籃子(群組)後,這時你只想要那些一籃超過十顆的籃子。
範例:
SELECT 籃子, COUNT(*)
FROM 蘋果
GROUP BY 籃子
HAVING COUNT(*) > 10;
這個查詢只會選出那些蘋果數量超過 10 顆的籃子。
主要差異:
| 特點 | WHERE |
HAVING |
|---|---|---|
| 應用時機 | 群組前先過濾資料列 | 群組後再過濾群組 |
| 聚合函數 | 不能用聚合函數 | 可以用聚合函數 |
| 目標 | 先把不需要的資料列去掉 | 把不符合條件的群組去掉 |
WHERE、GROUP BY 跟 HAVING 的執行順序
要更懂 WHERE 跟 HAVING 怎麼運作,來看一下 SQL 查詢的執行順序:
- 先執行
FROM,從資料表選出資料列。 - 接著用
WHERE,只留下符合條件的資料列。 - 然後用
GROUP BY做群組,得到新的群組資料表。 - 再來用
HAVING,只留下符合條件的群組。 - 最後才是
SELECT把結果選出來。
簡單畫一下流程:
1. FROM → 2. WHERE → 3. GROUP BY → 4. HAVING → 5. SELECT
範例:
SELECT department, AVG(age) AS avg_age
FROM students
WHERE age > 18
GROUP BY department
HAVING AVG(age) > 20;
這裡發生了什麼:
- 在
students資料表裡,先選出age > 18的資料列(用WHERE)。 - 剩下的資料列用
department來群組。 - 每個群組算出學生的平均年齡。
- 平均年齡小於或等於 20 的群組被
HAVING排除。 - 最後把結果顯示出來。
組合用法範例
範例 1:群組前後都過濾
條件:找出學生人數超過 5 人的科系,而且只算年齡大於 18 歲的學生。
原始資料表 students
| id | name | department | age | gpa |
|---|---|---|---|---|
| 1 | Alex Lin | ComputerSci | 20 | 3.8 |
| 2 | Maria Chi | Math | 22 | 3.5 |
| 3 | Anna Song | ComputerSci | 19 | 4.0 |
| 4 | Otto Art | Math | 17 | 3.9 |
| 5 | Liam Park | Physics | 21 | 3.7 |
| 6 | Jane Doe | ComputerSci | 23 | 3.6 |
| 7 | Tom Brown | Math | 25 | 3.4 |
| 8 | Sara White | Math | 19 | 3.8 |
| 9 | John Smith | ComputerSci | 20 | 3.7 |
| 10 | Emily Green | Physics | 18 | 3.9 |
| 11 | Mark Blue | ComputerSci | 21 | 3.5 |
| 12 | Zoe Black | Math | 22 | 3.6 |
| 13 | Max Gray | ComputerSci | 20 | 3.9 |
| 14 | Eva Gold | Math | 23 | 3.7 |
| 15 | Nick Silver | Physics | 19 | 3.8 |
查詢:
SELECT department, COUNT(*) AS student_count
FROM students
WHERE age > 18
GROUP BY department
HAVING COUNT(*) > 5;
結果: -- 查詢結果
| department | student_count |
|---|---|
| ComputerSci | 6 |
說明:
- 先把
age <= 18的資料列刪掉(WHERE條件)。 - 用
department來群組(GROUP BY department)。 - 算出每個群組的學生數。
- 把學生數小於或等於 5 的群組去掉(
HAVING COUNT(*) > 5)。
範例 2:用 WHERE 取代 HAVING 的錯誤
條件:找出平均年齡超過 22 歲的科系。
錯誤查詢:
SELECT department, AVG(age) AS avg_age
FROM students
WHERE AVG(age) > 22
GROUP BY department;
錯誤:SQL 不允許在 WHERE 裡用聚合函數 AVG,因為這時聚合還沒算出來。
正確查詢:
SELECT department, AVG(age) AS avg_age
FROM students
GROUP BY department
HAVING AVG(age) > 22;
這裡 AVG(age) > 22 是在群組後才套用的條件。
實用小技巧
如果你要過濾的是 資料列,就用 WHERE。範例:找出薪水超過 5000 的員工。
SELECT *
FROM employees
WHERE salary > 5000;
如果你要過濾的是 群組,就用 HAVING。範例:找出總薪水超過 100000 的部門。
SELECT department, SUM(salary) AS total_salary
FROM employees
GROUP BY department
HAVING SUM(salary) > 100000;
複雜條件就同時用 WHERE 跟 HAVING。
範例:找出總人口超過一千萬的國家,只算人口超過一百萬的城市。
SELECT country, SUM(population) AS total_population
FROM cities
WHERE population > 1000000
GROUP BY country
HAVING SUM(population) > 10000000;
常見錯誤跟解法
最常見的錯誤之一就是把 WHERE 跟 HAVING 搞混。比如想在 WHERE 裡用聚合函數:
SELECT department, COUNT(*)
FROM students
WHERE COUNT(*) > 10
GROUP BY department;
這樣會報錯,因為聚合還沒算出來就用 WHERE。正確做法是用 HAVING:
SELECT department, COUNT(*)
FROM students
GROUP BY department
HAVING COUNT(*) > 10;
還有一種錯誤是條件放錯地方。比如:
SELECT department, AVG(age) AS avg_age
FROM students
WHERE avg_age > 20
GROUP BY department;
這裡 avg_age > 20 不對,因為 avg_age 還沒算出來。解法是把這個條件移到 HAVING:
SELECT department, AVG(age) AS avg_age
FROM students
GROUP BY department
HAVING AVG(age) > 20;
希望你現在已經很清楚 WHERE 跟 HAVING 的差別、怎麼正確用,還有怎麼避免常見錯誤。這些觀念對你寫複雜報表、分析資料、優化查詢都超有用。也就是說,幾乎你以後寫的 SQL 查詢一半都會用到啦 :)
GO TO FULL VERSION