SQL GROUP BYとHAVING — 集約とグループのフィルタリング
GROUP BYで行を集約し、HAVINGでグループをフィルタリングする方法。WHEREとHAVINGの違い、一般的な集約関数、例を解説します。
Clauses & Filters
詳細な説明
グループの集約とフィルタリング
GROUP BYは値を共有する行を1つの要約行にまとめます。HAVINGは集約後にグループをフィルタリングします — GROUP BYにとってのHAVINGは、SELECTにとってのWHEREと同じ関係です。
基本的なGROUP BY
SELECT department_id, COUNT(*) AS emp_count
FROM employees
GROUP BY department_id;
GROUP BYとHAVING
SELECT department_id, COUNT(*) AS emp_count
FROM employees
GROUP BY department_id
HAVING COUNT(*) > 5;
WHEREとHAVINGの比較
| 句 | フィルタ対象 | 実行タイミング |
|---|---|---|
| WHERE | 個別の行 | グルーピング前 |
| HAVING | グループ | グルーピング後 |
-- WHEREはグルーピング前に行をフィルタリング
-- HAVINGは集約後にグループをフィルタリング
SELECT department_id, AVG(salary) AS avg_salary
FROM employees
WHERE is_active = true -- まず行をフィルタ
GROUP BY department_id
HAVING AVG(salary) > 60000; -- 次にグループをフィルタ
複数の集約関数
SELECT
d.name AS department,
COUNT(*) AS headcount,
AVG(e.salary) AS avg_salary,
MIN(e.salary) AS min_salary,
MAX(e.salary) AS max_salary
FROM employees e
JOIN departments d ON e.department_id = d.id
GROUP BY d.name
ORDER BY avg_salary DESC;
複数カラムによるグルーピング
SELECT department_id, job_title, COUNT(*)
FROM employees
GROUP BY department_id, job_title;
よくある間違い
集約関数内にないSELECTのすべてのカラムは、GROUP BY句に含まれている必要があります。MySQLのONLY_FULL_GROUP_BYモード(5.7.5以降デフォルト)はこれを強制します。
ユースケース
商品カテゴリ別の合計売上、地域別の平均注文額、部署別の従業員数など、グループごとの集計統計を表示するダッシュボードを構築している場合。