
COUNT(*)とCOUNT(列名)で、結果が変わる理由
集計した件数が、テーブルの行数と合いませんでした。
SELECT COUNT(*) FROM reports; -- 100
SELECT COUNT(comment) FROM reports; -- 82同じテーブルに対して、COUNTを2通りの書き方で使っただけです。片方は100件、もう片方は82件。どちらかが間違っているのではなく、数えているものが違います。
COUNT(*)は、行そのものを数える
COUNT(*)は、条件に合った行の数を数えます。列の中身が何であるかは見ていません。NULL(値が入っていない状態)が入っている行も、そのまま1行として数えます。
COUNT(*) -- 該当する行数。NULLがあっても数えるCOUNT(列名)は、その列にNULLでない値がある行だけを数える
一方、COUNT(列名)と書くと、指定した列がNULLではない行だけを数えます。
先の例で言えば、reportsテーブルに100行あり、そのうちcomment列が空欄(NULL)の行が18行あった、ということです。COUNT(comment)はその18行を数えず、残りの82行だけを数えました。
-- comment列にNULLが混ざっている場合
COUNT(*) -- 100(全行)
COUNT(comment) -- 82(commentがNULLでない行だけ)使い分けを間違えると、集計が誤った意味を持つ
この違いを知らずに書くと、集計の意味そのものが変わってしまいます。
-- 「コメントを書いた人数」を知りたいのに
SELECT COUNT(*) FROM reports WHERE reporter = '営業部';
-- これは「営業部からの報告件数」であって、コメントの有無は見ていない
-- コメントを書いた件数を知りたいなら
SELECT COUNT(comment) FROM reports WHERE reporter = '営業部';「件数」という言葉が、何の件数を指しているかを先に決めておく必要があります。「報告があった件数」なのか、「コメント欄に記入があった件数」なのかで、使うCOUNTの書き方が変わります。
DISTINCTと組み合わせると、さらに意味が変わる
COUNTはDISTINCT(重複を除く指定)と組み合わせることもできます。
SELECT COUNT(DISTINCT reporter) FROM reports;これは「reporter列に何種類の値があるか」、つまり報告した人の実人数を数えます。COUNT(*)が「報告の件数」を数えるのとは、まったく違う問いに答えています。1人が何度も報告していれば、COUNT(*)とCOUNT(DISTINCT reporter)の差が、そのまま「1人あたりの平均報告回数」の手がかりになります。
読むときに見るところ
1. COUNT(*)とCOUNT(列名)が混在しているSQLを見たら、書いた人がどちらの数を意図したかを確認する
2. 対象の列にNULLが入りうるかどうかを、テーブル定義かデータを見て確認する。NULLが存在しない列なら、COUNT(*)とCOUNT(列名)の結果は一致する
3. 「件数」という言葉が出てきたら、行の件数なのか、ある列に値がある件数なのか、重複を除いた種類数なのかを区別する
4. 集計結果がテーブルの行数と合わないときは、まずCOUNTの対象とNULLの有無を疑う
COUNT(*)とCOUNT(列名)は、見た目が似ているだけで別の質問に答える関数です。どちらを使うかは、知りたい数字が何なのかで決まります。