SQLでは、行をそのまま読むだけでなく、件数、合計、平均などを集計できます。その中心になるのが GROUP BY です。
一言でいうと
GROUP BYは、行をグループに分けて、グループごとにCOUNTやSUMを計算するための仕組みです。
集計関数
まず、代表的な集計関数を整理します。
| 関数 | 意味 |
|---|---|
COUNT(*) | 行数を数える |
SUM(col) | 合計する |
AVG(col) | 平均する |
MIN(col) | 最小値 |
MAX(col) | 最大値 |
たとえば、注文の件数を数えるSQLです。
SELECT COUNT(*) AS order_count
FROM orders;
GROUP BYとは
GROUP BY は、同じ値を持つ行をまとめます。
SELECT user_id, COUNT(*) AS order_count
FROM orders
GROUP BY user_id;
これは、ユーザーごとの注文数を数えるSQLです。
| user_id | order_count |
|---|---|
| 1 | 2 |
| 2 | 1 |
| 3 | 5 |
GROUP BYを使うと、結果は「元の行」ではなく「グループごとの行」になります。
WHEREとHAVINGの違い
WHERE と HAVING はどちらも絞り込みですが、タイミングが違います。
| 句 | いつ絞るか | 例 |
|---|---|---|
WHERE | 集計する前 | 2026年の注文だけにする |
HAVING | 集計した後 | 注文数が3件以上のユーザーだけにする |
SELECT user_id, COUNT(*) AS order_count
FROM orders
WHERE ordered_at >= '2026-01-01'
GROUP BY user_id
HAVING COUNT(*) >= 3;
このSQLは、2026年以降の注文だけを対象にし、その中で注文数が3件以上のユーザーを取得します。
SELECTに書ける列
GROUP BY を使うときは、SELECT に書ける列に注意が必要です。
SELECT user_id, COUNT(*)
FROM orders
GROUP BY user_id;
これは自然です。user_id ごとにまとめているため、user_id と集計結果を表示できます。
一方、グループ化していない列をそのまま出すと、どの行の値を表示すればよいか曖昧になります。
SELECT user_id, status, COUNT(*)
FROM orders
GROUP BY user_id;
このようなSQLは、多くのデータベースでエラーになります。status も表示したいなら、GROUP BY user_id, status のようにグループに含めます。
集計SQLの読む順番
集計SQLは、次の順番で読むと整理しやすいです。
FROMで対象テーブルを見るWHEREで集計前に不要な行を除くGROUP BYでグループを作るSELECTでグループごとの値を出すHAVINGで集計後に絞るORDER BYで並べる
よくある誤解
| 誤解 | 実際 |
|---|---|
WHERE COUNT(*) >= 3 と書ける | 集計結果の条件は HAVING に書きます |
GROUP BY は並び替え | グループ化であり、並び替えは ORDER BY です |
COUNT(col) と COUNT(*) は常に同じ | COUNT(col) はNULLを数えません |
| SELECTに何でも列を書ける | グループ化していない列は扱えません |
まとめ
GROUP BY は、行をグループに分けて集計するために使います。WHERE は集計前の絞り込み、HAVING は集計後の絞り込みです。集計SQLは、元の行を見るのではなく、グループごとの結果を見るものとして考えると理解しやすくなります。