SQLの集計(集計関数・GROUP BY・HAVING)
集計関数(COUNT・SUM・AVG・MAX・MIN)の値を表から計算でき、GROUP BY・HAVING・ORDER BY の穴埋め問題で正しい組み合わせを選べるようになる。
「部署ごとの売上合計」「月ごとの件数」のような集計は、管理画面やレポートの裏で毎日動いている SQL です。科目Aでは、GROUP BY と HAVING の穴埋め問題と、表を見て集計値を計算する問題がくり返し出ています。
このレッスンで稽古する(用語チェック・過去問)結論:集計は「グループに分ける→1グループを1行にまとめる」
集計関数は、たくさんの行を1つの値にまとめる関数です。GROUP BY は、まとめる前に行をグループ分けする句です。HAVING は、まとめた後のグループを条件で絞り込む句です。
たとえば、レシートの山を「店ごと」に箱へ仕分けて(GROUP BY)、箱ごとに合計金額を出し(SUM)、合計1万円以上の箱だけ残す(HAVING)、という流れです。
集計関数5つ:何を数えるか
| 関数 | 返す値 | 出庫記録の例(数量 3,2,1,2) |
|---|---|---|
| COUNT(*) | 行の数 | 4 |
| COUNT(列) | その列が NULL(値なし)でない行の数 | 4 |
| SUM(列) | 合計 | 3+2+1+2 = 8 |
| AVG(列) | 平均(合計÷件数) | 8÷4 = 2 |
| MAX(列) / MIN(列) | 最大 / 最小 | 3 / 1 |
COUNT は中身の数値を見ずに行を数えます。 数量が3でも100でも、1行は1と数えます。WHERE があれば、条件に合う行だけを集計します。
SQLが処理される順番
書く順番と処理される順番は違います。この順番が分かると、「WHERE に集計関数を書けない」理由が分かります。
flowchart LR
A["FROM 表を読む"] --> B["WHERE 行を絞る"]
B --> C["GROUP BY グループ分け"]
C --> D["HAVING グループを絞る"]
D --> E["SELECT 列と集計値を出す"]
E --> F["ORDER BY 並べ替え"]
WHERE が動く時点では、まだグループ分けも集計もしていません。そのため、WHERE AVG(点数) >= 80 は書けません。集計した結果で絞るときは、必ず HAVING を使います。
WHERE と HAVING の違い(最頻出)
| WHERE | HAVING | |
|---|---|---|
| 絞る対象 | 1行ずつ | グループ(集計後) |
| 実行タイミング | GROUP BY の前 | GROUP BY の後 |
| 集計関数を書けるか | 書けない | 書ける |
| 例 | WHERE 点数 >= 80(80点以上の答案だけ) |
HAVING AVG(点数) >= 80(平均80点以上の学生だけ) |
「平均が80点以上の学生」は、平均を出してからでないと判定できないので HAVING です。WHERE 点数 >= 80 と書くと「80点以上の科目だけで平均を出す」という別の処理になり、80点未満の科目がある学生まで残ってしまいます。
GROUP BY のルール:SELECT の列と一致させる
SELECT に書く列は、集計関数の中に入れるか、GROUP BY に書くかのどちらかにします。グループを1行にまとめるので、グループ内で値がそろわない列は表示できないからです。
- ○
SELECT 注文日, AVG(数量) … GROUP BY 注文日 - ×
SELECT 注文日, AVG(数量) … GROUP BY 数量(注文日が1つの値に決まらない) - ×
AVG(SUM(数量))(集計関数の入れ子は不可) - ×
WHERE SUM(数量) > 1000(WHERE に集計関数は書けない)
GROUP BY に複数の列を書くと、その組み合わせごとに1グループになります。「クラスごと、教科ごと」なら GROUP BY クラス名, 教科名 です。ここに学生番号を足すと、1人ずつのグループになり、平均を出す意味がなくなります。
ORDER BY:最後に並べ替える
ORDER BY は結果の並び順を指定します。書かなければ昇順(ASC:小さい順)で、降順にしたいときは DESC を付けます。「クラス名、教科名の昇順」と言われたら ORDER BY クラス名, 教科名 です。
ORDER BY は SELECT の後に動くので、AS 平均点 で付けた別名も使えます。ただし試験では「問題文に書かれた並び順と同じ列を指定しているか」だけを確認すれば十分です。
試験での問われ方
- 集計値の比較:表と4つの SQL が示され、「最も大きな値はどれか」と問われる。COUNT(*) の行数を数量の値と取り違えさせる問題
- GROUP BY・HAVING の穴埋め:「学生ごと」「クラスごと・教科ごと」という問題文から、グループ化する列と、条件を HAVING に書くか WHERE に書くかを選ばせる
- GROUP BY・ORDER BY の穴埋め:グループに余計な列(学生番号・平均点)を足した選択肢や、並び順の列が問題文と違う選択肢でひっかける
- グループの数:表を示し、複数の列でグループ化したときのグループ数を数えさせる
- 構文の正誤:SELECT の列と GROUP BY の列が合っていない、集計関数を入れ子にしている、WHERE に集計関数を書いている、のどれかが誤りの選択肢になる
4つの集計値を計算して比べる
| 商品番号 | 日付 | 数量 |
|---|---|---|
| NP200 | 2015-10-10 | 3 |
| FP233 | 2015-10-10 | 2 |
| NP200 | 2015-10-11 | 1 |
| FP233 | 2015-10-11 | 2 |
ア SELECT AVG(数量) FROM 出庫記録 WHERE 商品番号 = 'NP200'
イ SELECT COUNT(*) FROM 出庫記録
ウ SELECT MAX(数量) FROM 出庫記録
エ SELECT SUM(数量) FROM 出庫記録 WHERE 日付 = '2015-10-11'
解き方と答えを見る
- 表を確認する:NP200/10-10/3、FP233/10-10/2、NP200/10-11/1、FP233/10-11/2 の4行
- ア AVG(数量) WHERE 商品番号='NP200':対象は3と1 → (3+1)÷2 = 2
- イ COUNT(*):行の数を数える → 4行なので 4
- ウ MAX(数量):3,2,1,2 の最大 → 3
- エ SUM(数量) WHERE 日付='2015-10-11':対象は1と2 → 1+2 = 3
- 比べる:ア2、イ4、ウ3、エ3 → 最大はイ
答え:イ(COUNT(*) = 4)。数量の最大値3や合計3と、行数4を混同しないこと。
2つの列でグループ化したときのグループ数
| 伝票コード | 商品コード | 販売価格 | 数量 | 税区分 |
|---|---|---|---|---|
| D000 | S000 | 1,000 | 1 | Z000 |
| D000 | S001 | 1,100 | 2 | Z000 |
| D000 | S002 | 1,200 | 3 | Z008 |
| D001 | S003 | 1,200 | 1 | Z008 |
| D001 | S004 | 1,100 | 2 | Z010 |
| D001 | S005 | 1,000 | 3 | Z010 |
ア 3
イ 4
ウ 5
エ 6
出典:基本情報技術者試験 科目A免除 修了試験 20260726 実施分 問21
解き方と答えを見る
- グループ化する列は伝票コードと税区分の2つ → 2つの値の組み合わせが同じ行を1グループにする
- 1行ずつ組み合わせを書き出す:(D000,Z000)(D000,Z000)(D000,Z008)(D001,Z008)(D001,Z010)(D001,Z010)
- 重複を除く:(D000,Z000)、(D000,Z008)、(D001,Z008)、(D001,Z010)
- 数える → 4グループ
答え:イ(4)。伝票コードだけなら2、税区分だけなら3になるが、それはひっかけ。
「学生ごと・平均80点以上」の穴埋め
ア 科目 HAVING AVG(点数) >= 80
イ 科目 WHERE 点数 >= 80
ウ 学生番号 HAVING AVG(点数) >= 80
エ 学生番号 WHERE 点数 >= 80
解き方と答えを見る
- 「学生ごとに平均」→ グループは学生 → GROUP BY 学生番号(アとイは科目なので除外)
- 「平均が80点以上」→ 集計した後の条件 → HAVING AVG(点数) >= 80
- WHERE 点数 >= 80 は1行ずつの条件なので、「平均80点以上」という意味にならない(エは除外)
答え:ウ(学生番号 HAVING AVG(点数) >= 80)
要点(試験直前に読む)
- COUNT(*) は行数。中身の数値は見ない。表の問題では、まず行を数える
- 処理順は FROM→WHERE→GROUP BY→HAVING→SELECT→ORDER BY
- 集計結果の条件(AVG(点数) >= 80 など)は HAVING に書く。WHERE には集計関数を書けない
- SELECT の列は、集計関数の中に入れるか GROUP BY に書くかのどちらか
- 「AごとBごと」なら GROUP BY A, B。グループ数は (A,B) の組み合わせが何種類あるかで数える
- 並び順の指定は ORDER BY で、既定は昇順
ひっかけ
- COUNT(*) の行数を、数量の合計や最大値と取り違える → COUNT は1行を1と数えるだけ
- 集計後の条件を WHERE に書いた選択肢 → 集計関数が条件に入っていれば HAVING
- GROUP BY に学生番号や平均点などの余計な列が入っている → 問題文の「〜ごと」に出てくる列だけを書く
- 2つの列でグループ化したのに、片方の列の種類数だけを数える → 組み合わせを書き出して重複を除く
- 集計関数の入れ子(AVG(SUM(…)))や、SELECT と GROUP BY の列が合わない構文 → どちらも誤り
用語(14)
複数の行の値をまとめて1つの値(件数・合計・平均・最大・最小)にする関数。
条件に合う行の数を返す関数で、列の値の大きさには関係しない。
⚠ SUM(値の合計)と混同しやすい。COUNT は行数、SUM は中身の数値の合計。
指定した列が NULL でない行だけを数える関数。
⚠ COUNT(*) は NULL の行も含めて全部の行を数える。
指定した列の値の合計を返す関数。
⚠ COUNT と区別する。数量3の行は SUM では3、COUNT では1と数える。
指定した列の値の平均(合計÷件数)を返す関数。
指定した列の最大値/最小値を返す関数。
値が入っていないことを表す特別な状態で、0や空文字とは別のもの。
⚠ 0 とは違う。COUNT(列) や AVG は NULL の行を計算に入れない。
指定した列の値(複数指定ならその組み合わせ)が同じ行を1つのグループにまとめる句。
⚠ ORDER BY は並べ替えるだけで、行をまとめない。
GROUP BY でまとめた後のグループを、集計値などの条件で絞り込む句。
⚠ WHERE は集計前に1行ずつ絞る。集計関数を条件に使うなら HAVING。
グループ化の前に、表の行を1行ずつ条件で絞り込む句。
⚠ HAVING と違い、集計関数を書けない。
結果の行を指定した列の順に並べ替える句で、既定は昇順。
⚠ GROUP BY と違い、グループ化はしない。
ORDER BY で指定する並び順で、ASC は昇順(小さい順)、DESC は降順(大きい順)。
⚠ 何も書かなければ ASC になる。
SELECT で出す列や集計値に、表示用の名前を付ける指定。
GROUP BY に書いた列のことで、SELECT ではこの列か集計関数の結果だけを表示できる。
⚠ グループ化列に学生番号などを足すと、グループが細かくなりすぎて集計の意味が変わる。
このレッスンの過去問
- SQL集計関数(COUNT・AVG・MAX・SUM)の結果比較基本情報技術者試験 科目A免除 修了試験 20111218 実施分 問30
- SQLのGROUP BY句とHAVING句平成31年度 春期 基本情報技術者試験 午前 問27
- SQLのGROUP BY句とORDER BY句による集計と整列基本情報技術者試験 科目A免除 修了試験 20260125 実施分 問20
- SQLのGROUP BY句の集計(選択列とグループ化列の一致)基本情報技術者試験 科目A免除 修了試験 20260726 実施分 問21