結論:集計関数(COUNT/SUM/AVG/MAX/MIN)は「たくさんの行を1つの答えにまとめる」道具で、GROUP BY はそれを「グループごとに」実行するスイッチです。 つまり GROUP BY category と書けば、カテゴリごとに SUM(price) を計算してくれる――この一点さえ掴めば、あとは実際に集計してみて表がどう縮むかを目で見るだけでほぼ理解できます。
このサイトの SQL コースはブラウザの中で本物の SQL がそのまま動きます(登録不要・環境構築なし・無料)。読みながら手を動かせるので、下のリンク先はどれも「読む」より「実行する」ためのページだと思ってください。
まず集計関数だけを理解する(GROUP BY なし)
集計関数は、たくさんの行を受け取って1つの値を返します。代表は5つです。
COUNT(*)… 行の数を数えるSUM(列)… 合計AVG(列)… 平均MAX(列)/MIN(列)… 最大・最小
たとえば SELECT COUNT(*) FROM products; は「商品テーブルに何行あるか」を返し、SELECT AVG(price) FROM products; は「平均価格」を返します。ポイントは、結果が必ず1行になること。何百行あっても、まとめて1つの答えに畳み込むわけです。
この「行を畳み込む」感覚は文章で読むより一度実行したほうが早いです。詳しくは 集計関数 ― たくさんの行を1つの答えに をブラウザでそのまま実行してみてください。COUNT・SUM・AVG を書き換えて、結果が1行に縮む様子を確かめられます。
なお集計の前段として SELECT(列を取り出す)と WHERE(条件で絞る)が分かっていると理解が早いです。あやしければ SELECT ― 列を取り出す と WHERE ― 条件で絞り込む に戻ってから進みましょう。
GROUP BY は「グループごとに集計する」スイッチ
集計関数だけだと「全体の合計」しか出せません。でも実務で欲しいのはたいてい「カテゴリごとの合計」「会員ごとの注文数」のような、グループ別の集計です。ここで登場するのが GROUP BY です。
SELECT category, SUM(price)
FROM products
GROUP BY category;
これは「category が同じ行どうしをまとめ、まとまりごとに SUM(price) を計算する」という意味です。冒頭の図のとおり、6行が「本」「食品」の2行に畳み込まれます。GROUP BY に書いた列が結果の1行1グループになる、と覚えてください。
手を動かすなら GROUP BY ― グループごとに集計する が最短です。グループにする列を変えると結果の行数が変わるので、「何でまとめているか」を体感できます。
覚えておくルール:SELECT に書ける列
GROUP BY category を書いたら、SELECT に並べていいのは基本的に**「GROUP BY した列」か「集計関数」だけ**です。SELECT category, name, SUM(price) のように、グループの代表値でない生の列(name)を混ぜるとエラーになったり、意図しない値が返ったりします。これは初心者が最初に必ずぶつかる壁です。
HAVING は「集計した後で」絞り込む
「合計が1000円を超えるカテゴリだけ見たい」――このとき WHERE SUM(price) > 1000 と書きたくなりますが、これは動きません。WHERE はグループにまとめる前の1行ずつに効くフィルタで、まだ合計が計算されていないからです。
集計した後の値で絞り込むのが HAVING です。
SELECT category, SUM(price)
FROM products
GROUP BY category
HAVING SUM(price) > 1000;
WHERE(集計前)と HAVING(集計後)の使い分けは、SQL が句を評価する順番(FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY)を知ると腑に落ちます。この実行順序ごと HAVING と実行順序 ― 集計結果で絞り込む で実際に動かして確かめるのがおすすめです。
つまずきやすいところ
- GROUP BY していない生の列を SELECT に入れてしまう … 一番多いつまずきです。MySQL などでは
ERROR 1055になります。原因と直し方は SQLのエラー逆引き:GROUP BY の誤り を参照してください。 - WHERE で集計結果を絞ろうとする … 前述のとおり集計後の条件は
HAVING。エラーメッセージが出たら SQLのエラー一覧 から近いものを探すと早いです。 - COUNT と NULL の関係 …
COUNT(*)は行数を数えますが、COUNT(列)はその列が NULL でない行だけを数えます。NULL は集計から静かに外れるので、件数が合わないときはここを疑ってください。「値が無い」の扱いは NULLとは(Wiki用語集) にまとめています。
集計結果を読みやすくする
集計した列は SUM(price) のような名前で表示されて読みにくいので、AS で別名を付けると実務っぽくなります(例:SUM(price) AS 合計金額)。計算列と別名の付け方は 計算列と別名(AS)― 取り出しながら計算する で試せます。
ひととおり掴んだら、実データで手を動かすのが定着の近道です。総合演習① ― 売上を集計する は、ここで学んだ GROUP BY と集計関数をまとめて使う実践回になっています。
次に読む
- 集計関数 ― たくさんの行を1つの答えに(COUNT/SUM/AVG/MAX/MIN の基本・実行できる)
- GROUP BY ― グループごとに集計する(グループ別集計・実行できる)
- HAVING と実行順序 ― 集計結果で絞り込む(WHERE との違い・実行できる)
- SQLのエラー逆引き:GROUP BY の誤り(詰まったときの逆引き)
- SQL(データ操作)コースのトップ(第0章からブラウザで実行できます)
SQL コースは全編ブラウザで実行できるので、この記事を読みながら SQL 文を書き換えて試すと一気に身につきます。無料・登録不要で、いますぐ SQLコース を開いて手を動かしてみてください。