SQL練習室
← SQLガイド

SQLのGROUP BYとは?部署ごとの件数・合計・平均を結果表で解説

GROUP BYは、同じ値を持つ行をまとめて集計する構文です。社員5人の一覧から「部署ごとの人数や月給の合計」を作れます。どの社員が同じグループになり、結果が何行になるかを確かめましょう。

例で使う表

employeesの1行が社員1人分です。営業が2人、開発が2人、サポートが1人います。salaryは月給(円)で、恵比寿さんのNULLは月給が未入力であることを表し、0円とは区別します。すべての例でこの5人を使います。結果表の行の並びは一例です。ORDER BYで指定しない限り、表示順は保証されません。

employees:社員5人の一覧(salaryは月給・円)
id(社員ID)name(名前)department(部署)salary(月給)
1青木営業300000
2北野開発400000
3中央営業350000
4大和開発400000
5恵比寿サポートNULL

GROUP BYの基本構文

sql
SELECT department, COUNT(*) AS people
FROM employees
GROUP BY department;

部署ごとにまとめてCOUNTで人数を数える

GROUP BY departmentで部署が同じ社員をまとめ、COUNT(*)でその人数を数えます。営業は青木さんと中央さんの2人、開発も2人、サポートは1人です。元の5行が部署ごとの3行になります。AS peopleは人数の結果列に付けた名前です。

sql
SELECT department, COUNT(*) AS people
FROM employees
GROUP BY department;
実行結果
departmentpeople
サポート1
営業2
開発2

SUMで部署ごとの月給を合計する

COUNT(*)をSUM(salary)に変えると、人数の代わりに月給を合計します。営業は300000 + 350000で650000円、開発は400000 + 400000で800000円です。サポートは月給がNULLの1人だけなので、合計もNULLになります。

sql
SELECT department, SUM(salary) AS total_salary
FROM employees
GROUP BY department;
実行結果
departmenttotal_salary
サポートNULL
営業650000
開発800000

AVGで部署ごとの平均月給を求める

AVG(salary)は、入力されている月給の合計をその件数で割ります。営業の平均は650000 ÷ 2で325000円、開発は400000円です。NULLを0円として計算するわけではなく、入力値のないサポートは平均もNULLです。

sql
SELECT department, AVG(salary) AS average_salary
FROM employees
GROUP BY department;
実行結果
departmentaverage_salary
サポートNULL
営業325000
開発400000

MIN・MAXで部署の月給の幅を見る

MINは最小値、MAXは最大値です。営業では300000円と350000円、開発では全員が同額なので両方とも400000円になります。表示されるのは金額であり、その金額を受け取る社員名ではありません。

sql
SELECT department,
  MIN(salary) AS lowest_salary,
  MAX(salary) AS highest_salary
FROM employees
GROUP BY department;
実行結果
departmentlowest_salaryhighest_salary
サポートNULLNULL
営業300000350000
開発400000400000

COUNT(*)とCOUNT(salary)の違いを確かめる

COUNT(*)は社員の行を数え、COUNT(salary)は月給がNULLでない行だけを数えます。サポートには社員が1人いるのでpeopleは1ですが、入力済み月給の件数は0です。「人数」と「値が入っている件数」を区別しましょう。

sql
SELECT department,
  COUNT(*) AS people,
  COUNT(salary) AS entered_salaries
FROM employees
GROUP BY department;
実行結果
departmentpeopleentered_salaries
サポート10
営業22
開発22

COUNT DISTINCTで月給が何種類あるかを数える

COUNT(DISTINCT salary)は、重複を除いた月給の種類数です。営業は300000円と350000円の2種類、開発は2人とも400000円なので1種類になります。NULLは数えないためサポートは0です。

sql
SELECT department, COUNT(DISTINCT salary) AS salary_types
FROM employees
GROUP BY department;
実行結果
departmentsalary_types
サポート0
営業2
開発1

複数列で「部署と月給」の組み合わせ別にまとめる

GROUP BY department, salaryとすると、部署だけでなく月給も同じ社員をまとめます。営業は月給が違うので2グループに分かれ、開発の2人は同じグループです。部署だけの3行から、結果が4行へ増える点に注目してください。

sql
SELECT department, salary, COUNT(*) AS people
FROM employees
GROUP BY department, salary;
実行結果
departmentsalarypeople
サポートNULL1
営業3000001
営業3500001
開発4000002

WHEREで集計する社員を先に絞る

月給35万円以上の社員だけを数えるなら、GROUP BYの前にWHEREを書きます。営業の青木さんと、月給が未入力の恵比寿さんが集計対象から外れます。その結果、営業は1人、開発は2人になり、サポートの行はなくなります。

sql
SELECT department, COUNT(*) AS people
FROM employees
WHERE salary >= 350000
GROUP BY department;
実行結果
departmentpeople
営業1
開発2

実際に1問解いてみる

GROUP BY・COUNT(*)

employeesの部署ごとの人数を、department、COUNT(*)の順で取得してください。行順は問いません。

テーブル

読み込み中…

実行結果

関連構文

GROUP BYについてよくある質問

社員名もSELECTに書いてよいですか?
部署だけでまとめると、営業の名前を青木と中央のどちらにするか決まりません。この例でnameをそのままSELECTに加えるとエラーになります。社員ごとの行を残したい場合は、ウィンドウ関数のガイドを参照してください。
0人の部署も表示できますか?
この社員表に存在しない部署は、GROUP BYだけでは表示されません。部署の一覧を別に用意してLEFT JOINする方法があります。
DISTINCTとの違いは?
部署名の重複を除くだけならDISTINCTで十分です。部署ごとの人数や金額も計算したいときにGROUP BYを使います。

参考文献

内容はPostgreSQL公式ドキュメントを参照し、初めて学ぶ人向けに日本語で整理しています。