GROUP BY:將結果集依指定欄位分組,配合聚合函數(COUNT、SUM、AVG 等)進行統計。
HAVING:對分組後的聚合結果進行篩選,類似 WHERE 但作用於分組層級。
關鍵規則:SELECT 清單中的非聚合欄位,必須出現在 GROUP BY 子句中。
員工工作記錄表 employee_tbl:
+------+------+------------+--------------------+ | id | name | work_date | daily_typing_pages | +------+------+------------+--------------------+ | 1 | John | 2007-01-24 | 250 | | 2 | Ram | 2007-05-27 | 220 | | 3 | Jack | 2007-05-06 | 170 | | 3 | Jack | 2007-04-06 | 100 | | 4 | Jill | 2007-04-06 | 220 | | 5 | Zara | 2007-06-06 | 300 | | 5 | Zara | 2007-02-06 | 350 | +------+------+------------+--------------------+
SELECT name, COUNT(*) AS work_days FROM employee_tbl GROUP BY name;
結果:
+------+-----------+ | name | work_days | +------+-----------+ | Jack | 2 | | Jill | 1 | | John | 1 | | Ram | 1 | | Zara | 2 | +------+-----------+
SELECT name, COUNT(*) AS work_days FROM employee_tbl GROUP BY name HAVING COUNT(*) > 1;
結果:
+------+-----------+ | name | work_days | +------+-----------+ | Jack | 2 | | Zara | 2 | +------+-----------+
| 特性 | WHERE | HAVING |
|---|---|---|
| 執行順序 | 分組前過濾 | 分組後過濾 |
| 可用聚合函數 | 不可 | 可 |
| 適用場景 | 原始資料篩選 | 統計結果篩選 |
| 別名支援 | 不可用 | 可用(MySQL 擴展) |
-- 統計各部門各職級平均薪資,僅顯示平均薪資 > 50000 且人數 >= 3 的群組 SELECT department, level, AVG(salary) AS avg_salary, COUNT(*) AS emp_count FROM employees WHERE hire_date < '2023-01-01' -- 先過濾入職早於某日期的員工 GROUP BY department, level HAVING AVG(salary) > 50000 AND COUNT(*) >= 3 ORDER BY avg_salary DESC;
-- 找出各部門薪資前 3 高的員工
WITH ranked AS (
SELECT
name, department, salary,
ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS rn
FROM employees
)
SELECT name, department, salary
FROM ranked
WHERE rn <= 3;
APPROX_COUNT_DISTINCT)