4. GROUP BY編:データを集計する¶
4.1. GROUP BYとは¶
GROUP BYは、データをグループ化して集計するための機能です。
例えば以下のようなことができます:
クラスごとの平均点を計算
教科ごとの最高点・最低点を確認
生徒ごとの合計点でランキング作成
4.2. 集計の基本¶
まずは基本的な集計関数を見てみましょう。
4.2.1. よく使う集計関数¶
-- 全生徒の数学の平均点
SELECT
AVG(score) AS "平均点"
FROM scores
INNER JOIN subjects ON scores.subject_id = subjects.subject_id
WHERE subjects.subject_name = '数学'
AND scores.exam_id = 1;
このクエリでは GROUP BYを省略 しています。GROUP BYを省略すると:
テーブル全体を1つのグループとして扱う
結果は必ず1行になる
SELECTには集計関数のみ指定可能(通常のカラムは指定できない)
つまり、「全体の合計」や「全体の平均」を求める場合はGROUP BYは不要です。
主な集計関数:
COUNT()
- 件数を数えるSUM()
- 合計を計算AVG()
- 平均を計算MAX()
- 最大値を取得MIN()
- 最小値を取得
4.2.2. GROUP BYで分類して集計¶
クラスごとの平均点を計算してみます。
GROUP BYの動作イメージ:
実際のSQLクエリ:
SELECT
classes.grade AS "学年",
classes.class_name AS "クラス",
AVG(scores.score) AS "平均点"
FROM scores
INNER JOIN students ON scores.student_id = students.student_id
INNER JOIN classes ON students.class_id = classes.class_id
WHERE scores.exam_id = 1 -- 1学期中間テスト
GROUP BY classes.class_id
ORDER BY classes.grade, classes.class_name;
ポイント:
GROUP BY
で指定したカラムごとにグループ化SELECTに含める非集計カラムは、すべてGROUP BYに含める必要がある
4.3. 実用的な集計例¶
4.3.1. 教科別の成績分析¶
各教科の平均点、最高点、最低点を一度に取得:
SELECT
subjects.subject_name AS "教科",
COUNT(scores.score) AS "受験者数",
AVG(scores.score) AS "平均点",
MAX(scores.score) AS "最高点",
MIN(scores.score) AS "最低点"
FROM scores
INNER JOIN subjects ON scores.subject_id = subjects.subject_id
WHERE scores.exam_id = 1
GROUP BY subjects.subject_id, subjects.subject_name
ORDER BY subjects.subject_id;
4.3.2. 生徒の成績ランキング¶
生徒ごとの5教科合計点でランキングを作成:
SELECT
students.last_name || ' ' || students.first_name AS "生徒名",
classes.grade AS "学年",
classes.class_name AS "クラス",
SUM(scores.score) AS "合計点"
FROM scores
INNER JOIN students ON scores.student_id = students.student_id
INNER JOIN classes ON students.class_id = classes.class_id
WHERE scores.exam_id = 1
GROUP BY students.student_id, classes.class_id
ORDER BY SUM(scores.score) DESC
LIMIT 10;
4.4. HAVINGで集計結果を絞り込む¶
平均点が70点以上の生徒のみを表示:
SELECT
students.last_name || ' ' || students.first_name AS "生徒名",
AVG(scores.score) AS "平均点"
FROM scores
INNER JOIN students ON scores.student_id = students.student_id
WHERE scores.exam_id = 1
GROUP BY students.student_id, students.last_name, students.first_name
HAVING AVG(scores.score) >= 70
ORDER BY AVG(scores.score) DESC;
WHERE
と HAVING
の違い:
WHERE
- グループ化前のデータを絞り込むHAVING
- グループ化後の集計結果を絞り込む
4.5. 実践的な応用例¶
4.5.1. クラス別成績表の作成¶
クラスごと、教科ごとの平均点を一覧表示します。
複数カラムでのGROUP BY:
実際のSQLクエリ:
SELECT
classes.grade AS "学年",
classes.class_name AS "クラス",
subjects.subject_name AS "教科",
ROUND(AVG(scores.score), 1) AS "平均点"
FROM scores
INNER JOIN students ON scores.student_id = students.student_id
INNER JOIN classes ON students.class_id = classes.class_id
INNER JOIN subjects ON scores.subject_id = subjects.subject_id
WHERE scores.exam_id = 1
GROUP BY
classes.class_id,
subjects.subject_id
ORDER BY
classes.grade, classes.class_name, subjects.subject_id;
ROUND()
関数で小数点第1位まで表示しています。
4.6. 実践演習¶
以下の問題にチャレンジしてみてください:
演習1: 各クラスの生徒数を表示してください
-- ヒント: students, classesをJOINして、COUNT()を使う
SELECT ...
演習2: 数学で80点以上を取った生徒が最も多いクラスを見つけてください
-- ヒント: WHERE句で絞り込んでからGROUP BY、ORDER BYで並び替え
SELECT ...
4.7. まとめ¶
GROUP BY編で学んだこと:
GROUP BY
でデータをグループ化して集計できるCOUNT()
、SUM()
、AVG()
などの集計関数を使うHAVING
で集計結果を絞り込めるJOINと組み合わせることで、複雑な集計も可能
これでJOINとGROUP BYの基本をマスターしました。実際の業務でも頻繁に使う重要な機能です。