【SQL】GROUP BY:グループに切り分ける
- 「〜によってグループ分けする」という意味
/* 商品分類が入っている行の数 */
SELECT COUNT(shohin_bunrui)
FROM Shohin;
count
-------
8
/* 商品分類ごとにグループ分け */
SELECT shohin_bunrui, COUNT(*)
FROM Shohin
GROUP BY shohin_bunrui;
shohin_bunrui | count
---------------+-------
キッチン用品 | 4
衣服 | 2
事務用品 | 2
GROUP BY句に指定する列:集約キー、グループ化列と呼ぶ
NULLが含まれていた場合
例:集約キー(shiire_tanka)にはNULLが含まれている
SELECT shiire_tanka
FROM Shohin;
/* NULLが2つ含まれている */
shiire_tanka
--------------
500
320
2800
2800
5000
-- NULL
790
-- NULL
(8 rows)
/* GROUP BYを使わない場合 */
SELECT COUNT(shiire_tanka)
FROM Shohin;
count
-------
6
/* GROUP BYを使った場合 */
SELECT shiire_tanka, COUNT(*)
FROM Shohin
GROUP BY shiire_tanka;
shiire_tanka | count
--------------+-------
| 2 -- NULL
320 | 1
500 | 1
2800 | 2
5000 | 1
790 | 1
「NULL」は1つのグループとして分類されるようになっている
注意:
COUNT(*)はNULLを含み、COUNT(列名)はNULLを含まない
WHERE句と使う
【実行順序】
- FROM テーブルを選ぶ
- WHERE 行を絞り込む ← 集約前。集約関数は書けない
- GROUP BY グループに分ける
- HAVING グループを絞り込む ← 集約後。集約関数が書ける
- SELECT 列を選ぶ ← ここで初めて別名が付く
- ORDER BY 並べ替える
SELECT shiire_tanka, COUNT(*)
FROM Shohin
WHERE shohin_bunrui = '衣服'
GROUP BY shiire_tanka;
shiire_tanka | count
--------------+-------
500 | 1
2800 | 1
よくある間違い
①SELECT文に余計な列を書く
COUNTのような集約関数を使った場合、SELECT句に書ける要素は限定される
【OKな要素】
- 定数
- 集約関数
GROUP BY句で指定した列名(つまり集約キー)
/* NG */
SELECT shohin_mei, shiire_tanka, COUNT(*)
FROM Shohin
GROUP BY shiire_tanka;
ERROR: column "shohin.shohin_mei" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: SELECT shohin_mei, shiire_tanka, COUNT(*)
/* エラー内容
列"shohin.shohin_mei"は`GROUP BY`句で出現しなければならないか
集約関数内で使用しなければなりません */
②GROUP BY句で列の別名を書く
SELECT句に「AS」で表示用の別名をつけることができるGROUP BY句でこの別名を使うことはできない(エラーになる)
PostgreSQLでは実行できるけど、他のDBMSではエラーとなるので使わない
SELECT shohin_bunrui AS sb, COUNT(*)
FROM Shohin
GROUP BY sb;
/* PostgreSQLの場合のみ */
sb | count
--------------+-------
キッチン用品 | 4
衣服 | 2
事務用品 | 2
③GROUP BY句は結果の順序をソートする?
- 取得結果の順序は保証されていない
- 同じ
SELECT文を実行しても、同じように並ばないことがある - 結果のレコード順がどんな規則に従っているのかはまったくわからない
④WHERE句に集約関数を書く
これは初心者が陥りがちな間違いらしい
/* 例:商品分類ごとにグループ化する */
SELECT shohin_bunrui, COUNT(*)
FROM Shohin
GROUP BY shohin_bunrui;
shohin_bunrui | count
---------------+-------
キッチン用品 | 4
衣服 | 2
事務用品 | 2
↑ここから、count = 2 のレコードを取得したい。。。
/* NG */
SELECT shohin_bunrui, COUNT(*)
FROM Shohin
WHERE COUNT(*) = 2
GROUP BY shohin_bunrui;
ERROR: aggregate functions are not allowed in WHERE
LINE 3: WHERE COUNT(*) = 2
/* エラー内容
`WHERE`句では集約を使用できません */
集約関数が書けるのは、SELECT句、HAVING句、ORDER BY句のみ
GROUP BYのあとで、count = 2の条件にあったレコードを選択したい
HAVING句で条件指定できる!
/* HAVINGで条件指定(2行の商品分類を選択) */
SELECT shohin_bunrui, COUNT(*)
FROM Shohin
GROUP BY shohin_bunrui
HAVING COUNT(*) = 2;
/* キッチン用品が正しく除外された */
shohin_bunrui | count
---------------+-------
衣服 | 2
事務用品 | 2
関連記事:【SQL】HAVING:集約後の条件指定
参考書籍:ミック『SQL 第2版 ゼロからはじめるデータベース操作』(翔泳社)