Query Go
件数・合計・平均を計算 - COUNT / SUM / AVG / MIN / MAX の使い方・オプション・サンプル

件数・合計・平均を計算 - COUNT / SUM / AVG / MIN / MAX

基本の集約関数。COUNT(*) と COUNT(col) の違い、NULL を無視する性質を理解する

概念図

COUNT / SUM / AVG / MIN / MAX diagram

構文

sql
COUNT(*), COUNT(col), SUM(col), AVG(col), MIN(col), MAX(col)

サンプル

基本集約関数の使い方まとめ

sql
SELECT
  COUNT(*)           AS total_rows,
  COUNT(email)       AS with_email,
  COUNT(DISTINCT country) AS country_cnt,
  AVG(age)           AS avg_age,
  MIN(created_at)    AS first_signup
FROM users;

COUNT(*) と COUNT(col) の違い

COUNT(*)行数そのものを数えます。列の値が NULL でもカウントされます。

COUNT(col)col が NULL でない行だけを数えます。「メールアドレスが登録されているユーザー数」のような用途で使います。

COUNT(DISTINCT col) で重複を除いたユニーク数を数えられます(NULL は除外)。

sql
-- 登録済みメールが何件あるか (NULL を除外)
SELECT COUNT(email) FROM users;

-- ユニークな国コードの数
SELECT COUNT(DISTINCT country) FROM users;

SUM / AVG と NULL

SUM / AVG / MIN / MAX はいずれも NULL を無視して計算します。NULL を 0 として扱いたければ COALESCE(col, 0) でラップしてください。

特に AVG は注意が必要で、AVG(col) は「NULL を除いた行数で割る」動作です。NULL を 0 とみなしたいなら SUM(COALESCE(col,0)) / COUNT(*) と書きます。

全行 NULL のときの挙動

対象行がすべて NULL、あるいは 1 行も該当しない場合、SUM / AVG / MIN / MAXNULL を返すのが標準です。一方 COUNT は 0 を返します。

「合計が 0 でなく NULL になった」と困ることは実運用で意外と多いので、COALESCE(SUM(x), 0) のように明示的に 0 にしておくと安全です。

FILTER 句 / CASE での条件集約

「ステータスごとの件数を 1 クエリで」のように 条件別の集約 をしたいときは 2 つの書き方があります。

  • SQL 標準の FILTER 句 (PostgreSQL / SQLite 3.30+): COUNT(*) FILTER (WHERE status = 'done')
  • CASE 式 (全 RDBMS): SUM(CASE WHEN status = 'done' THEN 1 ELSE 0 END)

MySQL / SQL Server は FILTER 未対応なので CASE 方式が安全です。

sql
-- ポータブルな条件集約
SELECT
  COUNT(*)                                           AS total,
  SUM(CASE WHEN status = 'done'    THEN 1 ELSE 0 END) AS done_cnt,
  SUM(CASE WHEN status = 'pending' THEN 1 ELSE 0 END) AS pending_cnt
FROM tasks;

落とし穴

  • COUNT(1) は COUNT(*) より速い?: 現代の DB ではどちらも同じ実行計画。好みの問題
  • AVG の整数割り算: MySQL / SQL Server で INT 列の AVG は DECIMAL になるが、意図しない丸めに注意
  • MIN/MAX に文字列: 辞書順になる。数字の文字列 '10' < '2' にハマりがち

関連トピック