#07 MySQLデータベースを使ってみよう
集計する — GROUP BY
集計とは
データベースには大量のレコードが蓄積されます。「カテゴリ別の商品数は?」「ユーザーごとの注文合計は?」といった集計を行うには、 GROUP BY? 指定した列の値が同じ行をまとめてグループ化する句。COUNT・SUM・AVGなどの集計関数と組み合わせて使う。「カテゴリ別の件数を集計」などに使用する。 と 集計関数? グループや全行に対して計算を行う関数。COUNT(件数)・SUM(合計)・AVG(平均)・MAX(最大)・MIN(最小)がある。GROUP BY と組み合わせて使うことが多い。 関数を使います。
サンプルデータ
CREATE TABLE orders (
id INT NOT NULL AUTO_INCREMENT,
user_id INT NOT NULL,
category VARCHAR(50) NOT NULL,
product VARCHAR(200) NOT NULL,
total DECIMAL(10, 2) NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
INSERT INTO orders (user_id, category, product, total) VALUES
(1, '電子機器', 'ノートPC', 89800),
(1, 'PC周辺機器', 'マウス', 3200),
(2, 'PC周辺機器', 'キーボード', 12000),
(2, '電子機器', 'タブレット', 54000),
(3, '電子機器', 'モニター', 45000),
(3, 'PC周辺機器', 'USBハブ', 2500),
(4, '家電', '電気ケトル', 8000),
(4, '家電', '空気清浄機', 35000);
GROUP BY — グループ化して集計
GROUP BY は指定したカラムの値が同じ行をひとまとめにします。
-- カテゴリ別の注文件数
SELECT category, COUNT(*) AS 注文件数
FROM orders
GROUP BY category;
+----------------+----------+
| category | 注文件数 |
+----------------+----------+
| 電子機器 | 3 |
| PC周辺機器 | 3 |
| 家電 | 2 |
+----------------+----------+
集計関数
COUNT — 件数を数える
-- 全注文件数
SELECT COUNT(*) AS 総注文数 FROM orders;
-- NULL を除いたカラムの件数(*との違い)
SELECT COUNT(user_id) AS ユーザーID件数 FROM orders;
-- ユニークな値の数
SELECT COUNT(DISTINCT user_id) AS ユニークユーザー数 FROM orders;
SUM — 合計を求める
-- カテゴリ別の売上合計
SELECT category, SUM(total) AS 売上合計
FROM orders
GROUP BY category
ORDER BY 売上合計 DESC;
AVG — 平均を求める
-- ユーザー別の平均注文金額
SELECT user_id, AVG(total) AS 平均注文金額
FROM orders
GROUP BY user_id;
MAX / MIN — 最大・最小を求める
-- カテゴリ別の最高・最低価格
SELECT
category,
MAX(total) AS 最高金額,
MIN(total) AS 最低金額,
COUNT(*) AS 件数
FROM orders
GROUP BY category;
HAVING — 集計後に絞り込む
WHERE は集計前の行に条件をかけますが、集計後の結果に条件をかけるには HAVING を使います。
-- 売上合計が20000円以上のカテゴリのみ表示
SELECT category, SUM(total) AS 売上合計
FROM orders
GROUP BY category
HAVING SUM(total) >= 20000;
+------------+----------+
| category | 売上合計 |
+------------+----------+
| 電子機器 | 188800 |
| PC周辺機器 | 17700 |
| 家電 | 43000 |
+------------+----------+
WHERE vs HAVING の使い分け
-- WHERE: 集計「前」に絞り込む(高速)
-- HAVING: 集計「後」に絞り込む
-- ❌ HAVINGで書けるがWHEREより遅い
SELECT category, SUM(total)
FROM orders
GROUP BY category
HAVING category = '電子機器';
-- ✅ カテゴリの絞り込みはWHEREで先に行う
SELECT category, SUM(total)
FROM orders
WHERE category = '電子機器'
GROUP BY category;
両方を使う例
-- アクティブユーザー(user_id >= 2)の中で
-- 合計購入金額が30000円以上のユーザーを取得
SELECT user_id, SUM(total) AS 合計購入金額
FROM orders
WHERE user_id >= 2 -- 集計「前」に絞り込む(WHERE)
GROUP BY user_id
HAVING SUM(total) >= 30000 -- 集計「後」に絞り込む(HAVING)
ORDER BY 合計購入金額 DESC;
GROUP BY + JOIN の組み合わせ
-- ユーザー名と注文集計を一緒に取得
SELECT
u.name,
COUNT(o.id) AS 注文件数,
SUM(o.total) AS 合計金額,
AVG(o.total) AS 平均金額
FROM users AS u
LEFT JOIN orders AS o ON o.user_id = u.id
GROUP BY u.id, u.name
ORDER BY 合計金額 DESC;
WITH ROLLUP — 小計・合計行を追加する
WITH ROLLUP を使うと、グループごとの小計や全体合計行が自動で追加されます。
SELECT category, SUM(total) AS 売上合計
FROM orders
GROUP BY category WITH ROLLUP;
+----------------+----------+
| category | 売上合計 |
+----------------+----------+
| PC周辺機器 | 17700 |
| 家電 | 43000 |
| 電子機器 | 188800 |
| NULL | 249500 | ← 全体合計
+----------------+----------+
最後の NULL の行が全体合計です。COALESCE を使って見た目を整えることもできます。
SELECT
COALESCE(category, '【全体合計】') AS カテゴリ,
SUM(total) AS 売上合計
FROM orders
GROUP BY category WITH ROLLUP;
まとめ
GROUP BYで同じ値の行をグループ化して集計するCOUNT(*): 件数、SUM(): 合計、AVG(): 平均、MAX()/MIN(): 最大/最小WHEREは集計前の行を絞り込む(高速)HAVINGは集計後の結果を絞り込むWITH ROLLUPで小計・合計行を自動追加できる
次回はバックアップ取得とユーザー管理でシリーズを締めくくります。