第08回: GROUP BYと集計関数 — アプリ側ループで集計するのはもう終わりにする

章: 第2章: 実務クエリ基礎

「ユーザーごとの投稿数」をPHP側でカウントしていませんか?

全投稿を取得してPHPの配列で count() するコードは、データが増えるほどメモリと処理時間を消費します。1万件のレコードを全件取得してアプリ側で集計するのは、DB本来の仕事をわざわざ横取りしている状態です。

GROUP BY と集計関数を使えば、DBが集計まで完結してくれます。 アプリには結果だけを渡せばよく、コードもシンプルになります。

GROUP BY で集計できる主な関数

GROUP BY はテーブルの行をグループ化し、各グループに対して集計関数を適用します。SELECT に書ける非集計列は、GROUP BY に書いたカラムのみという制約(ONLY_FULL_GROUP_BY)に注意が必要です。

主な集計関数の比較

関数 用途 NULL の扱い
COUNT(*) 全行数をカウント NULLの行も数える
COUNT(col) 特定列の非NULL行数 NULLをスキップ
SUM(col) 合計値 NULLを無視して計算
AVG(col) 平均値 NULLを除外して計算
MAX(col) 最大値 NULLを無視
MIN(col) 最小値 NULLを無視

チェックポイント: COUNT(*)COUNT(col) は挙動が異なります。NULLを含むカラムを集計するときは COUNT(col) を使い、NULL行を除外した件数を取得しましょう。意図せず全件カウントになるミスを防げます。

実際のコードのサンプル


SELECT user_id, COUNT(*) AS post_count, MAX(created_at) AS last_posted_at
FROM posts
GROUP BY user_id
ORDER BY post_count DESC;

まとめ & 次のステップ

  • GROUP BY はテーブルの行をグループ化し、各グループに集計関数を適用する
  • SELECT に書ける非集計列は GROUP BY に含めたカラムのみ(ONLY_FULL_GROUP_BY)
  • COUNT(*)(全行)と COUNT(col)(非NULL行)は別物。NULLの扱いに注意する
  • アプリ側での集計ループはDB側のGROUP BYに置き換えることでパフォーマンスが改善する

次回は 「HAVING句の使い所」 を学びます。集計後の結果をさらに絞り込む HAVING と WHERE の使い分けを正しく理解します。

Related Articles