メインコンテンツへスキップ
見出し画像

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(列名)は、見た目が似ているだけで別の質問に答える関数です。どちらを使うかは、知りたい数字が何なのかで決まります。

     
     
    プログラマー・SE歴10年。PC・Excelのつまずきと、小さな店・ネット販売・イベント・ひとり仕事の「数が合わない」を、手順と記録表にして書いています。無料で最初の一手、有料で完全版。迷ったら固定表示のガイドへ。

    あなたへのおすすめ