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以降デフォルト)はこれを強制します。

ユースケース

商品カテゴリ別の合計売上、地域別の平均注文額、部署別の従業員数など、グループごとの集計統計を表示するダッシュボードを構築している場合。

試してみる — SQL Cheat Sheet

フルツールを開く