Q1集計関数 COUNT / SUM / AVG / MIN / MAX を 1 つだけ SELECT に書いて実行したとき、結果の行数は基本的にどうなりますか。
集計関数 — COUNT / SUM / AVG / MIN / MAX
SQL の集計関数 COUNT / SUM / AVG / MIN / MAX を、CSV の成績データで全体集計から WHERE 併用まで、ブラウザで実行しながら学べます。
本記事で使うデータ — score テーブル
本記事の 集計関数(集約関数とも呼ぶ。複数行をまとめて 1 つの値にする関数)では、何行あるか、合計はいくつか、平均は、最小・最大は——というように、多数の行を 1 つの数値に圧縮 します。COUNT / SUM / AVG / MIN / MAX の 5 つが基本で、レポートの集計値はほぼこれだけで作れます。
題材は score テーブル(30 行 = 10 名 × Math / English / Science の 3 科目)です。score 列の点数を対象に、全体の集計と、WHERE で対象を絞ってからの集計を順に試します。グループごとの集計(科目別平均など)は次の記事で扱うので、本記事は テーブル全体/WHERE で絞った範囲全体を 1 つの値にまとめる ところに集中します。
集計関数は「多数の行 → 1 つの値」
集計関数は SELECT の列の位置に書きます。
ここで気をつけたいのが、素の列と集計関数を同じ `SELECT` に混ぜない ことです。name のような素の列は 行ごとに値が違います が、COUNT(*) などの集計関数は テーブル全体(または `WHERE` で絞った全体)を 1 つの値に畳みます。SELECT name, COUNT(*) FROM score; のように両方を書くと、集計側は全体で 1 値なのに name は「どの行の値を出すか」が決まりません。多くのデータベースではこれは エラー になります。
score の 30 行を入力として、COUNT は行数、SUM は合計、AVG は平均、MIN / MAX は最小・最大を、それぞれ 1 つの値 として返します。-- 件数・種類数・合計・平均をまとめて取得
SELECT
COUNT(*) AS row_count,
COUNT(DISTINCT name) AS name_kinds,
SUM(score) AS total,
AVG(score) AS avg_raw
FROM score
WHERE subject = 'English';
COUNT(*) と COUNT(列) の違い
COUNT(*) は 行数そのもの を数えます。COUNT(列) は その列が NULL でない行だけ を数えます。score テーブルには NULL がないため両者は同じ 30 になりますが、NULL を含む列ではここに差が出ます(後半で NULL のある表を使って確かめます)。さらに COUNT(DISTINCT 列) と書くと 重複を除いた種類数 を数えられます(subject に対して使えば科目の種類数 3 が得られます)。
Tips — 集計関数と NULL
SUM / AVG / MIN / MAX は NULL の行を計算に入れません(無視します)。とくに AVG は「NULL でない値の合計 ÷ NULL でない件数」で計算されます。そのため NULL を含む列では、SUM(列) / COUNT(*)(分母が全行数)と AVG(列)(分母が NULL でない件数)は 値がずれます。NULL を 0 とみなして平均したいときは AVG(COALESCE(列, 0)) のように明示します。
WHERE で対象を絞ってから集計する
WHERE を付けると、条件に合う行だけ が集計関数の入力になります。実行順序は「FROM で全行を読む → WHERE で行を絞る → 残った行を集計関数でまとめる」です。つまり集計関数が見るのは WHERE を通過した行だけで、絞り込みの後に合計や平均が計算されます。WHERE subject = 'Math' を付ければ Math の 10 行だけが対象になり、平均は Math だけの平均になります。
FROM で 30 行を読み、WHERE subject = 'Math' で 10 行に絞り、その 10 行だけを AVG(score) がまとめます。集計は 絞り込みの後 に行われます。-- Science の 10 行だけの 件数 / 平均 / 最高点
SELECT
COUNT(*) AS row_count,
ROUND(AVG(score), 1) AS avg_science,
MAX(score) AS top_science
FROM score
WHERE subject = 'Science';
COUNT(列) と NULL、AVG の丸め
ここまでの score には NULL がありませんでした。NULL の有無で集計がどう変わるかを、欠損のある customer テーブル(8 名・age / email / country に NULL あり)で確かめます。COUNT(*) は 行数 なので 8 のままですが、COUNT(email) は email が入っている行だけを数えるため 4 になります。NULL を含む列を COUNT(列) すると、このように COUNT(*) より小さくなります。
また AVG は割り算なので 31.5 のように小数が出ます。レポートでは ROUND(AVG(age), 2) のように ROUND(式, 桁数) で丸めると扱いやすくなります。
customer(8 名)では、COUNT(*) は 8 のまま、COUNT(email) は email が入っている 4 行だけを数えます。NULL を含む列は COUNT(列) が COUNT(*) より小さくなります。-- NULL の有無で COUNT と AVG がどう変わるか
SELECT
COUNT(*) AS rows_all,
COUNT(country) AS with_country,
ROUND(AVG(age), 2) AS avg_age
FROM customer;
理解度チェック
まずは1問ずつ答えてみましょう。
Q2COUNT(*) と COUNT(列) の違いの説明として正しいものはどれですか。
Q3WHERE subject = 'Math' を付けて AVG(score) を実行すると、平均はどの範囲で計算されますか。