CodeGym /課程 /SQL SELF /用 HAVING 過濾聚合資料

用 HAVING 過濾聚合資料

SQL SELF
等級 8 , 課堂 1
開放

我們還沒聊過一個重點,就是 聚合完之後要怎麼過濾 group? 有時候我們不想看全部的學院,只想看學生超過一百人的那些。或者只想看平均薪水超過 50,000 的部門。今天就來認識一下怎麼用 HAVING 來過濾聚合資料。

那我們已經有 WHERE 了,為什麼還要 HAVING?不能直接把 WHERE 放在 GROUP BY 後面嗎 :)

沒那麼簡單啦!首先,SQL 的語法順序是固定的,WHERE 會在 GROUP BY 之前執行。

那能不能把它移到 GROUP BY 後面?

也不行!很多時候我們要先過濾資料,再分組,然後分組完再過濾一次。

那是不是可以直接複製 WHERE,改名叫 HAVING,然後放在 GROUP BY 後面?

沒錯,就是這樣!:)

HAVINGWHERE 的差別

WHERE 是在分組前過濾資料。

想像你在挑蛋糕口味:草莓跟巧克力的留下,其他都丟旁邊。這就是 WHERE 的工作。

HAVING 是在分組跟聚合完之後才過濾。

比如你已經把蛋糕分桌子,算好每桌有幾個蛋糕,現在只想留下蛋糕超過三個的桌子。

所以 HAVING針對 group 層級 的過濾。

HAVING 的語法

語法跟 WHERE 很像,但其實運作方式不一樣:

SELECT 欄位, 聚合函數
FROM 資料表
GROUP BY 欄位
HAVING 條件;

執行步驟:

  1. 先用 WHERE 過濾資料。
  2. 然後用 GROUP BY 分組。
  3. 對分組後的資料用聚合函數。
  4. 最後用 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 BYfaculty 分組。
  • 然後 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 聚合後的結果來過濾。

WHEREGROUP BYHAVING 的執行順序

WHEREHAVING 是在不同階段過濾資料。為了更清楚差別,來看一下查詢的步驟:

  1. WHERE:過濾資料列。

    這階段會處理所有資料列。沒通過 WHERE 條件的資料直接被丟掉。

  2. GROUP BY:分組。

    過濾完的資料會根據 GROUP BY 指定的欄位分組。

  3. 聚合函數:

    對分組後的資料用 COUNT()AVG()SUM() 等聚合函數。

  4. HAVING:過濾 group。

    這階段只處理聚合結果。HAVING 條件只對 group 有效。

HAVING 的特點

特點 1:能用聚合函數

HAVINGWHERE 最大的差別就是能用聚合函數。舉例:

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 有時候真的不夠用啦。

留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION