ITの教科書検索
入門読了 約9分

SQLのGROUP BYと集約関数とは ― HAVINGでの絞り込み

SQLのGROUP BYは、列の値が同じ行をまとめ、顧客ごとの件数や合計金額などを求める構文です。COUNT・SUMなどの集約関数と、WHEREとHAVINGの違いを図で確かめられます。

目次
  1. GROUP BYとは
  2. 集約関数の種類
  3. WHEREとHAVINGの違い
  4. 列と集約関数を選んで結果を見る
  5. 練習問題

GROUP BYとは、指定した列の値が同じ行をまとめる構文

SQLのGROUP BYとは、指定した列の値が同じ行を1つのグループにまとめる構文です。注文テーブルから「顧客ごとの注文件数」や「顧客ごとの合計金額」を求めたいときに使います。

SELECT文のWHEREは、行を1行ずつ見て、残すか除くかを決めます。一方、GROUP BYは、複数の行を1つのグループにまとめ、グループごとに1行の結果を返します。JOINで複数の表をつないだ結果や、UNION ALLで年ごとの売上を1つにまとめた結果を集計するときにも使います。

多くの場合、GROUP BYは集約関数と組み合わせます。集約関数を使うと、グループごとの件数・合計・平均などを計算できます。

集約関数は、COUNT・SUM・AVG・MAX・MINの5種類をよく使う

集約関数とは、複数の行の値を1つの値にまとめる関数です。よく使うのは、件数を数えるCOUNTと、合計・平均・最大値・最小値を求めるSUM・AVG・MAX・MINの5種類です。

集約関数の種類と、対象行が0件のときの結果
関数計算すること対象行が0件のとき
COUNT(*)行数を数える0
COUNT(列名)その列がNULLでない行数を数える0
SUM(列名)NULLでない値を合計するNULL
AVG(列名)NULLでない値の平均を求めるNULL
MAX(列名)・MIN(列名)NULLでない値の最大・最小を求めるNULL

COUNT(*)は、条件に合う行の数をそのまま数えます。COUNT(列名)は、その列の値がNULLでない行だけを数えます。数える列にNULLの行があると、COUNT(*)とCOUNT(列名)の結果が変わります。

SUM・AVG・MAX・MINは、指定した列のNULLでない値だけを対象に計算します。対象の行が1件も無いとき、COUNTは0を返しますが、SUM・AVG・MAX・MINは0ではなくNULLを返します。0件の合計を0だと思い込むと、結果を誤解します。

GROUP BYと組み合わせると、集約関数はグループごとに計算します。GROUP BYを書かずに集約関数だけを使うと、表全体が1つのグループになり、結果は1行になります。

GROUP BYを使うSELECT文では、SELECT句に書ける列が限られます。標準SQLでは、GROUP BYで指定した列と、集約関数に入れた列は書けます。それ以外の列は書けません。1つのグループの中に違う値が複数あると、どの値を返すかが決まらないためです。

集約関数の中にCASE式を入れると、条件に合う行だけを数えたり足したりできます。月別の売上を横に並べる集計も、この書き方で作れます。

行をまとめずに、各行の横に合計や順位を付けたいときは、ウィンドウ関数を使います。

WHEREは集計する前に行を絞り、HAVINGは集計した後にグループを絞る

WHEREとHAVINGはどちらも結果を絞る句ですが、絞るタイミングが違います。WHEREは、GROUP BYでまとめる前に、個別の行を条件で絞ります。HAVINGは、GROUP BYでまとめた後に、グループ(集計結果)を条件で絞ります。

元の行8行すべてWHERE行を絞るGROUP BYまとめて集計HAVINGグループを絞る結果集計する前に絞る集計した後に絞る元の行8行すべてWHERE行を絞るGROUP BYまとめて集計HAVINGグループを絞る結果集計する前に絞る集計した後に絞る
WHEREはGROUP BYより前に個別の行を絞り、HAVINGはGROUP BYより後にグループ(集計結果)を絞ります。処理される順番が違うため、HAVINGではSUM・COUNTなどの集約関数を条件に使えますが、WHEREでは使えません。

SELECT文を書くときはSELECTが先頭ですが、結果が決まる順番は、FROM、WHERE、GROUP BY、HAVING、SELECTです。実際に実行する手順はデータベース製品が決めるので、この順番と違うことがあります。

WHEREを処理する時点では、まだグループも集約関数の結果もありません。そのため、WHEREにSUM・COUNTなどの集約関数の結果を条件として書けません。集約関数の結果を条件にしたいときは、HAVINGを使います。

SELECT 顧客, SUM(金額) AS 合計
FROM 注文
GROUP BY 顧客
HAVING SUM(金額) >= 50000;

この文は、顧客ごとに金額を合計した後、合計が50000円以上の顧客だけを残します。HAVINGの条件には、SELECT句に書いていない集約関数(この例ならSUM(金額))も書けます。

列と集約関数を選んで、集計結果を見る

次の図で、まとめる列(顧客ごと・商品ごと)と集約関数を選ぶと、GROUP BY文と集計結果の表が変わります。どの組み合わせも同じ注文テーブルを使います。図は実際のデータベースには接続しておらず、結果はあらかじめ計算した固定の値です。AVGの結果は、小数第3位を四捨五入して表示しています。実際のデータベースでは、小数の桁数は製品や列の型によって変わります。

注文テーブル

注文ID顧客商品金額
1001田中美咲ノートPC98,000
1002田中美咲マウス1,200
1003佐藤健太マウス1,200
1004佐藤健太キーボード3,500
1005佐藤健太モニター15,000
1006鈴木大輔ノートPC92,000
1007鈴木大輔マウス1,500
1008田中美咲モニター16,000

まとめる列

集約関数

SELECT 顧客, SUM(金額) AS 集計結果
FROM 注文
GROUP BY 顧客;
実行結果(3行)
顧客集計結果
田中美咲115,200円
佐藤健太19,700円
鈴木大輔93,500円

参考にした資料

練習問題(全5問)

Q1GROUP BYの説明として最も適切なものはどれ?
Q2SUM(金額)で、対象の行が1件も無いときの結果はどれ?
Q3WHEREとHAVINGの違いとして正しいものはどれ?
Q4注文テーブルをGROUP BY 顧客 HAVING SUM(金額) >= 50000 としたとき、結果に残る条件はどれ?
Q5GROUP BY 顧客 としたSELECT文で、SELECT句にそのまま書けない列はどれ?

選んでから「採点する」を押すと、解説つきで答え合わせができます。

関連記事

おすすめの本 PR

セキュリティとデータベースは、基本情報技術者試験の対策本でまとめて学べます。

目的別の本の選び方を見る

データベースの記事を続けて読む

データベース 全36本中19本目