我們還沒聊過一個重點,就是 聚合完之後要怎麼過濾 group? 有時候我們不想看全部的學院,只想看學生超過一百人的那些。或者只想看平均薪水超過 50,000 的部門。今天就來認識一下怎麼用 HAVING 來過濾聚合資料。
那我們已經有 WHERE 了,為什麼還要 HAVING?不能直接把 WHERE 放在 GROUP BY 後面嗎 :)
沒那麼簡單啦!首先,SQL 的語法順序是固定的,WHERE 會在 GROUP BY 之前執行。
那能不能把它移到 GROUP BY 後面?
也不行!很多時候我們要先過濾資料,再分組,然後分組完再過濾一次。
那是不是可以直接複製 WHERE,改名叫 HAVING,然後放在 GROUP BY 後面?
沒錯,就是這樣!:)
HAVING 跟 WHERE 的差別
WHERE 是在分組前過濾資料。
想像你在挑蛋糕口味:草莓跟巧克力的留下,其他都丟旁邊。這就是 WHERE 的工作。
HAVING 是在分組跟聚合完之後才過濾。
比如你已經把蛋糕分桌子,算好每桌有幾個蛋糕,現在只想留下蛋糕超過三個的桌子。
所以 HAVING 是 針對 group 層級 的過濾。
HAVING 的語法
語法跟 WHERE 很像,但其實運作方式不一樣:
SELECT 欄位, 聚合函數
FROM 資料表
GROUP BY 欄位
HAVING 條件;
執行步驟:
- 先用
WHERE過濾資料。 - 然後用
GROUP BY分組。 - 對分組後的資料用聚合函數。
- 最後用
HAVING再過濾一次聚合結果。
HAVING 的使用範例
範例 1:過濾學生數多的學院
你想知道大學裡哪些學院學生超過 100 人。假設有個 students 資料表:
| id | name | faculty |
|---|---|---|
| 1 | Alice | Engineering |
| 2 | Bob | Engineering |
| 3 | Charlie | Arts |
| 4 | Daisy | Business |
| 5 | ... | ... |
查詢:
SELECT faculty, COUNT(*) AS student_count
FROM students
GROUP BY faculty
HAVING COUNT(*) > 100;
這裡發生了什麼:
- 先用
GROUP BY以faculty分組。 - 然後
COUNT(*)算每個學院有幾個學生。 - 最後
HAVING把學生數小於等於 100 的學院都丟掉。
結果:
| faculty | student_count |
|---|---|
| Engineering | 150 |
| Arts | 120 |
範例 2:平均薪水高的部門
你想找出平均薪水超過 50,000 的部門。假設有個 employees 資料表:
| id | name | department | salary |
|---|---|---|---|
| 1 | Alice | IT | 60000 |
| 2 | Bob | HR | 45000 |
| 3 | Charlie | IT | 70000 |
| 4 | Daisy | HR | 52000 |
| 5 | ... | ... | ... |
查詢:
SELECT department, AVG(salary) AS avg_salary
FROM employees
GROUP BY department
HAVING AVG(salary) > 50000;
結果:
| department | avg_salary |
|---|---|
| IT | 65000 |
注意:HAVING 是針對 GROUP BY 聚合後的結果來過濾。
WHERE、GROUP BY 跟 HAVING 的執行順序
WHERE 跟 HAVING 是在不同階段過濾資料。為了更清楚差別,來看一下查詢的步驟:
WHERE:過濾資料列。這階段會處理所有資料列。沒通過
WHERE條件的資料直接被丟掉。GROUP BY:分組。過濾完的資料會根據
GROUP BY指定的欄位分組。聚合函數:
對分組後的資料用
COUNT()、AVG()、SUM()等聚合函數。HAVING:過濾 group。這階段只處理聚合結果。
HAVING條件只對 group 有效。
HAVING 的特點
特點 1:能用聚合函數
HAVING 跟 WHERE 最大的差別就是能用聚合函數。舉例:
SELECT department, AVG(salary)
FROM employees
GROUP BY department
HAVING AVG(salary) > 50000;
這個查詢裡 AVG(salary) 不能寫在 WHERE,因為 WHERE 是在分組前執行的。像這樣寫:
SELECT department, AVG(salary)
FROM employees
WHERE AVG(salary) > 50000
GROUP BY department;
會報錯:aggregate functions are not allowed in WHERE。
特點 2:沒分組也能用 HAVING
你甚至可以不用 GROUP BY 也用 HAVING。這時候查詢會把所有資料當成一個 group:
SELECT AVG(salary) AS avg_salary
FROM employees
HAVING AVG(salary) > 50000;
實戰範例
假設我們有個商店,還有一個 sales 銷售資料表:
| id | product_id | sales_amount |
|---|---|---|
| 1 | 101 | 200.00 |
| 2 | 102 | 300.00 |
| 3 | 101 | 400.00 |
| 4 | 103 | 150.00 |
查詢:找出總銷售額超過 500 的商品。
SELECT product_id, SUM(sales_amount) AS total_sales
FROM sales
GROUP BY product_id
HAVING SUM(sales_amount) > 500;
結果:
| product_id | total_sales |
|---|---|
| 101 | 600.00 |
常見錯誤
在 WHERE 用聚合函數:
例如:
SELECT department, AVG(salary)
FROM employees
WHERE AVG(salary) > 50000
GROUP BY department;
錯誤:WHERE 不能用聚合函數。
跟 NULL 有關的錯誤:
如果資料有 NULL,過濾結果可能會怪怪的。例如:
SELECT department, SUM(salary)
FROM employees
GROUP BY department
HAVING SUM(salary) > 0;
如果 salary 欄位全都是 NULL,結果可能是 0 或空的。
恭喜你!你現在已經可以很穩地過濾聚合資料了!記得 HAVING 是你分析 group 層級資料的好幫手,WHERE 有時候真的不夠用啦。
GO TO FULL VERSION