CodeGym /課程 /SQL SELF /WHERE 跟 HAVING 的比較:執行順序解析與範例

WHERE 跟 HAVING 的比較:執行順序解析與範例

SQL SELF
等級 8 , 課堂 2
開放

我們再來複習一下 SQL 裡操作的執行順序,還有 WHERE 跟 HAVING 到底能做什麼、不能做什麼。這很重要,因為後面很多 SQL 查詢的細節都靠這個觀念。你一定要很熟才行啦。

那到底 WHEREHAVING 有什麼不一樣?什麼時候該用哪一個?它們又有什麼關聯?搞懂這些你才不會在查詢邏輯裡迷路,也能更有效率地過濾資料。來,我們把 WHEREHAVING 的知識整理一下。

什麼是 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
應用時機 群組前先過濾資料列 群組後再過濾群組
聚合函數 不能用聚合函數 可以用聚合函數
目標 先把不需要的資料列去掉 把不符合條件的群組去掉

WHEREGROUP BYHAVING 的執行順序

要更懂 WHEREHAVING 怎麼運作,來看一下 SQL 查詢的執行順序:

  1. 先執行 FROM,從資料表選出資料列。
  2. 接著用 WHERE,只留下符合條件的資料列。
  3. 然後用 GROUP BY 做群組,得到新的群組資料表。
  4. 再來用 HAVING,只留下符合條件的群組。
  5. 最後才是 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;

這裡發生了什麼:

  1. students 資料表裡,先選出 age > 18 的資料列(用 WHERE)。
  2. 剩下的資料列用 department 來群組。
  3. 每個群組算出學生的平均年齡。
  4. 平均年齡小於或等於 20 的群組被 HAVING 排除。
  5. 最後把結果顯示出來。

組合用法範例

範例 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

說明:

  1. 先把 age <= 18 的資料列刪掉(WHERE 條件)。
  2. department 來群組(GROUP BY department)。
  3. 算出每個群組的學生數。
  4. 把學生數小於或等於 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;

複雜條件就同時用 WHEREHAVING

範例:找出總人口超過一千萬的國家,只算人口超過一百萬的城市。

SELECT country, SUM(population) AS total_population
FROM cities
WHERE population > 1000000
GROUP BY country
HAVING SUM(population) > 10000000;

常見錯誤跟解法

最常見的錯誤之一就是把 WHEREHAVING 搞混。比如想在 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;

希望你現在已經很清楚 WHEREHAVING 的差別、怎麼正確用,還有怎麼避免常見錯誤。這些觀念對你寫複雜報表、分析資料、優化查詢都超有用。也就是說,幾乎你以後寫的 SQL 查詢一半都會用到啦 :)

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