集約とGROUP BY — データを集計する
SQLの集約関数(COUNT・SUM・AVG・MAX・MIN)とGROUP BYによるグループ集計、HAVINGでの絞り込みを基礎から解説します。WHEREとHAVINGの違いも整理します。
データを1行ずつ取り出すだけでなく、「部門ごとの平均給料」「地域別の売上合計」のようにまとめて集計したい場面はよくあります。これを担うのが集約関数と GROUP BY です。
集約関数
集約関数は、複数の行を受け取って1つの値を返す関数です。代表的なものは次のとおりです。
| 関数 | 意味 |
|---|---|
COUNT(*) | 行数を数える |
COUNT(列) | その列が NULL でない行数 |
SUM(列) | 合計 |
AVG(列) | 平均 |
MAX(列) / MIN(列) | 最大 / 最小 |
たとえば employees テーブル全体の人数と平均給料は、次のように求めます。
SELECT COUNT(*) AS num, AVG(salary) AS avg_salary
FROM employees;AS は結果の列に名前(別名)を付ける記法です。付けておくと結果が読みやすくなります。
GROUP BY — グループごとに集計する
「全体」ではなく「部門ごと」のように、あるまとまりごとに集計したいときは GROUP BY を使います。
SELECT dept, COUNT(*) AS num, AVG(salary) AS avg_salary
FROM employees
GROUP BY dept;これは dept(部門)ごとに行をまとめ、それぞれの人数と平均給料を計算します。結果は部門の数だけの行になります。
ここで大切なルールがあります。SELECT に書ける列は、GROUP BY に指定した列か、集約関数だけです。たとえば GROUP BY dept のときに SELECT name を書くことはできません(1つの部門に複数の名前があり、どれを返すか決まらないため)。
複数の列でグループ化することもできます。
SELECT region, category, SUM(quantity) AS total
FROM sales
GROUP BY region, category;これは「地域×カテゴリ」の組み合わせごとに数量を合計します。
WHERE と HAVING の違い
集計結果をさらに絞り込みたいときは HAVING を使います。よく混同されるので、WHERE との違いを整理します。
WHERE… グループ化する前に、個々の行を絞り込むHAVING… グループ化した後に、集計結果を絞り込む
たとえば「平均給料が 550 以上の部門だけ」を出すには HAVING を使います。
SELECT dept, AVG(salary) AS avg_salary
FROM employees
GROUP BY dept
HAVING AVG(salary) >= 550;一方、「入社年が 2020 年以降の社員だけを対象に、部門ごとの人数」を数えるなら、行を先に絞る WHERE を使います。
SELECT dept, COUNT(*) AS num
FROM employees
WHERE hire_year >= 2020
GROUP BY dept;両方を同時に使うこともできます。順序は WHERE → GROUP BY → HAVING です。
SELECT dept, AVG(salary) AS avg_salary
FROM employees
WHERE hire_year >= 2020
GROUP BY dept
HAVING AVG(salary) >= 550;集約と NULL
COUNT(*) は行数を数えますが、COUNT(列) はその列が NULL でない行だけを数えます。また SUM や AVG は NULL を無視して計算します。NULL の扱いは集計結果に影響するので、意図した対象を数えているか確認しましょう。
まとめ
- 集約関数(
COUNT/SUM/AVG/MAX/MIN)は複数行を1つの値にまとめる GROUP BYでまとまりごとに集計するSELECTに出せるのはGROUP BYの列か集約関数だけ- 行を絞るのは
WHERE、集計結果を絞るのはHAVING
集約は、データから傾向をつかむための基本技術です。「集約・グループ化」カテゴリの演習問題で、実際のデータを集計してみてください。