SQLのGROUP BYと集約関数とは ― HAVINGでの絞り込み
SQLの
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種類です。
| 関数 | 計算する | 対象行が |
|---|---|---|
| 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でまとめた後に、グループ(集計結果)を条件で絞ります。
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 | 田中美咲 | ノートPC | 98,000 |
| 1002 | 田中美咲 | マウス | 1,200 |
| 1003 | 佐藤健太 | マウス | 1,200 |
| 1004 | 佐藤健太 | キーボード | 3,500 |
| 1005 | 佐藤健太 | モニター | 15,000 |
| 1006 | 鈴木大輔 | ノートPC | 92,000 |
| 1007 | 鈴木大輔 | マウス | 1,500 |
| 1008 | 田中美咲 | モニター | 16,000 |
まとめる列
集約関数
SELECT 顧客, COUNT(*) AS 集計結果
FROM 注文
GROUP BY 顧客;| 顧客 | 集計結果 |
|---|---|
| 田中美咲 | 3件 |
| 佐藤健太 | 3件 |
| 鈴木大輔 | 2件 |
SELECT 顧客, SUM(金額) AS 集計結果
FROM 注文
GROUP BY 顧客;| 顧客 | 集計結果 |
|---|---|
| 田中美咲 | 115,200円 |
| 佐藤健太 | 19,700円 |
| 鈴木大輔 | 93,500円 |
SELECT 顧客, AVG(金額) AS 集計結果
FROM 注文
GROUP BY 顧客;| 顧客 | 集計結果 |
|---|---|
| 田中美咲 | 38,400円 |
| 佐藤健太 | 6,566.67円 |
| 鈴木大輔 | 46,750円 |
SELECT 顧客, MAX(金額) AS 集計結果
FROM 注文
GROUP BY 顧客;| 顧客 | 集計結果 |
|---|---|
| 田中美咲 | 98,000円 |
| 佐藤健太 | 15,000円 |
| 鈴木大輔 | 92,000円 |
SELECT 顧客, MIN(金額) AS 集計結果
FROM 注文
GROUP BY 顧客;| 顧客 | 集計結果 |
|---|---|
| 田中美咲 | 1,200円 |
| 佐藤健太 | 1,200円 |
| 鈴木大輔 | 1,500円 |
SELECT 商品, COUNT(*) AS 集計結果
FROM 注文
GROUP BY 商品;| 商品 | 集計結果 |
|---|---|
| キーボード | 1件 |
| ノートPC | 2件 |
| マウス | 3件 |
| モニター | 2件 |
SELECT 商品, SUM(金額) AS 集計結果
FROM 注文
GROUP BY 商品;| 商品 | 集計結果 |
|---|---|
| キーボード | 3,500円 |
| ノートPC | 190,000円 |
| マウス | 3,900円 |
| モニター | 31,000円 |
SELECT 商品, AVG(金額) AS 集計結果
FROM 注文
GROUP BY 商品;| 商品 | 集計結果 |
|---|---|
| キーボード | 3,500円 |
| ノートPC | 95,000円 |
| マウス | 1,300円 |
| モニター | 15,500円 |
SELECT 商品, MAX(金額) AS 集計結果
FROM 注文
GROUP BY 商品;| 商品 | 集計結果 |
|---|---|
| キーボード | 3,500円 |
| ノートPC | 98,000円 |
| マウス | 1,500円 |
| モニター | 16,000円 |
SELECT 商品, MIN(金額) AS 集計結果
FROM 注文
GROUP BY 商品;| 商品 | 集計結果 |
|---|---|
| キーボード | 3,500円 |
| ノートPC | 92,000円 |
| マウス | 1,200円 |
| モニター | 15,000円 |
参考にした資料
- PostgreSQL公式ドキュメント「SELECT」(SELECT文の処理順序、WHEREとHAVINGの違い、SELECT句に書ける列)
- Microsoft Learn「SELECT (Transact-SQL)」(SELECT文の論理的な処理順序)
- PostgreSQL公式ドキュメント「Aggregate Functions」(COUNT・SUM・AVG・MAX・MINの定義、対象行が0件のときにNULLを返すこと)
練習問題(全5問)
正解:指定した
GROUP BYは、
正解:NULL
COUNTを
正解:WHEREは
WHEREは
正解:顧客ごとに
HAVINGは、
正解:商品
標準SQLでは、
選んでから「採点する」を押すと、解説つきで答え合わせができます。
関連記事
おすすめの本 PR
セキュリティとデータベースは、基本情報技術者試験の対策本でまとめて学べます。

