SQLのGROUP BYを徹底解説!初心者でもデータの集計・グループ化がわかる基礎講座
生徒
「データベースからデータを取り出す方法は少しわかってきたのですが、例えば『クラスごとの平均点』とか『商品カテゴリーごとの売上合計』みたいに、データをまとめて計算したいときはどうすればいいんですか?」
先生
「それはとても大切な視点ですね。SQLには『GROUP BY(グループ・バイ)』という便利な命令があります。これを使うと、バラバラのデータを特定の共通点でグループ分けして、一気に計算することができるんですよ。」
生徒
「グループ分け……。難しそうですが、パソコン初心者でも覚えられますか?」
先生
「もちろんです。例えば、手元にある大量のレシートを『食費』『日用品』『娯楽費』という封筒に分ける作業をイメージしてみてください。その封筒ごとに中身の金額を合計する、という作業をSQLにやってもらうだけなんです。」
1. SQLとは何か?
SQL(エスキューエル)は、データベースと呼ばれる「大量のデータを整理して保存する箱」に対して指示を出すための言語です。例えば、会員名簿の中から特定の人を探したり、新しい人を追加したりするときに使います。プログラミング未経験の方でも、基本の型を覚えれば魔法のようにデータを操ることができます。今回はその中でも、データを集計して分析するために欠かせない技術を学んでいきましょう。
エンジニアの必須スキル「SQL」を、 図解と豊富な練習問題でゼロから体系的に学びたい人へ。 MySQLやPostgreSQLなど、各種データベースに対応した不朽の入門書です。
SQL 第2版 ゼロからはじめるデータベース操作をAmazonで見る※ Amazon広告リンク
2. GROUP BY(グループ化)のイメージを掴もう
SQLで最も強力な機能の一つが、このGROUP BYです。日本語に訳すと「~によってグループを作る」という意味になります。データベースの中にある膨大な行(レコード)を、指定した列の値が同じもの同士で一塊のグループにまとめる役割を持っています。
例えば、果物屋さんの売上データがあるとします。リンゴ、バナナ、リンゴ、イチゴ、バナナ……と売れた順に記録されている表を想像してください。この表をそのまま見ても「結局どの果物が一番売れたのか」はパッと分かりませんよね。そこで「果物の名前」でGROUP BYを実行すると、リンゴのグループ、バナナのグループ、イチゴのグループに整理されます。あとはそのグループごとに数を数えれば、売れ筋が一目でわかります。
3. データを集計するための「集計関数」を知る
GROUP BYを使うときにセットで覚えるべきなのが「集計関数(しゅうけいかんすう)」です。関数というと難しく聞こえますが、要するに「計算の種類」のことです。代表的なものは以下の通りです。
- COUNT(カウント):データの件数を数える。
- SUM(サム):数値の合計を出す。
- AVG(アベレージ):平均値を出す。
- MAX(マックス) / MIN(ミニマム):最大値や最小値を見つける。
4. 実践:商品カテゴリーごとに件数を数えてみよう
まずは、お店の在庫リストを使って、どのジャンルの商品が何種類あるか調べてみましょう。使用するのは「products(プロダクツ)」という名前のテーブルです。
実行前のテーブル状態
id | product_name | category | price
---+--------------+----------+-------
1 | リンゴ | 果物 | 150
2 | キャベツ | 野菜 | 200
3 | バナナ | 果物 | 100
4 | レタス | 野菜 | 180
5 | 牛乳 | 飲料 | 220
6 | トマト | 野菜 | 120
7 | オレンジ | 果物 | 130
このデータから、カテゴリー(果物・野菜・飲料)ごとに、何個の商品が登録されているかを集計します。SQLクエリは以下のようになります。
SELECT category, COUNT(*)
FROM products
GROUP BY category;
実行結果
category | COUNT(*)
---------+---------
果物 | 3
野菜 | 3
飲料 | 1
このように、カテゴリーごとにデータがキュッとまとまり、それぞれの件数が表示されました。これがGROUP BYの基本動作です。
5. 実践:部署ごとの給与合計を計算しよう
次に、会社の従業員データを使って、部署ごとにどれくらいの給料が支払われているのか、その合計(SUM)を計算してみましょう。「employees(エンプロイーズ)」テーブルを使います。
実行前のテーブル状態
id | name | department | salary
---+----------+------------+-------
1 | 田中さん | 営業部 | 300000
2 | 鈴木さん | 開発部 | 400000
3 | 佐藤さん | 営業部 | 280000
4 | 高橋さん | 総務部 | 250000
5 | 伊藤さん | 開発部 | 450000
6 | 渡辺さん | 営業部 | 320000
部署(department)でグループ分けし、給料(salary)の合計を求めます。
SELECT department, SUM(salary)
FROM employees
GROUP BY department;
実行結果
department | SUM(salary)
-----------+------------
営業部 | 900000
開発部 | 850000
総務部 | 250000
営業部の3人分の給料が合算され、一目で部署コストが把握できるようになりました。ビジネスの現場では非常によく使われる分析手法です。
6. 複数のテーブルを組み合わせるJOINと集計
さらにステップアップして、JOIN(ジョイン)という機能についても触れておきましょう。データベースでは、データを効率よく管理するために、あえて表を分けて保存することが一般的です。例えば「注文履歴の表」と「商品の詳細表」を別々に持っておき、必要な時だけ「商品ID」を鍵にしてつなぎ合わせるのです。これを「結合(けつごう)」と呼びます。
以下の例では、「売上データ(sales)」と「商品マスター(items)」をJOINして、商品名ごとの売上合計を出してみます。
売上データ:salesテーブル
sale_id | item_id | quantity
--------+---------+---------
101 | 1 | 2
102 | 2 | 1
103 | 1 | 5
104 | 3 | 3
商品マスター:itemsテーブル
item_id | item_name | price
--------+-----------+-------
1 | ノート | 100
2 | 消しゴム | 50
3 | ペン | 150
二つの表をJOINで合体させ、さらにGROUP BYで商品名ごとにまとめ、売上金額(単価×数量)を計算します。
SELECT items.item_name, SUM(items.price * sales.quantity) AS total_sales
FROM sales
JOIN items ON sales.item_id = items.item_id
GROUP BY items.item_name;
実行結果
item_name | total_sales
----------+------------
ノート | 700
消しゴム | 50
ペン | 450
ここで使った「AS total_sales」は、計算結果の列に分かりやすい名前(別名)を付けるための便利な機能です。これも覚えておくと、結果が見やすくなります。
7. GROUP BYを使うときの注意点
初心者が一番つまずきやすいポイントが「SELECTに書けるもの」のルールです。GROUP BYを使うときは、以下のものしか表示(SELECT)できません。
- GROUP BYに指定した列(例:カテゴリー名や部署名)
- 集計関数を使った計算結果(例:COUNTやSUMの結果)
グループ化したのに、そのグループに関係ない個人の名前などを無理やり表示しようとすると、コンピュータは「どの人の名前を出せばいいの?」と混乱してエラーになってしまいます。グループ全体の代表値を出す、という意識を持つことが成功のコツです。
8. 条件で絞り込むWHEREとHAVINGの違い
最後にもう一つ重要な知識です。データを絞り込むとき、通常はWHERE(ウェア)を使います。しかし、GROUP BYで集計した後の結果に対して「合計が500円以上のものだけ表示したい」といった条件を付けたいときは、HAVING(ハビング)という別の言葉を使います。
「グループ化する前に絞り込むのがWHERE」、「グループ化した後に絞り込むのがHAVING」と覚えましょう。この順番を間違えないことが、SQLマスターへの第一歩です。
例えば、先ほどの売上合計の例で「売上合計が500円以上の商品だけ」を表示したい場合は、以下のようになります。
SELECT items.item_name, SUM(items.price * sales.quantity) AS total_sales
FROM sales
JOIN items ON sales.item_id = items.item_id
GROUP BY items.item_name
HAVING SUM(items.price * sales.quantity) >= 500;
実行結果
item_name | total_sales
----------+------------
ノート | 700
条件に合致しない「ペン」と「消しゴム」が結果から消え、本当に知りたいデータだけが抽出されました。このようにSQLを組み合わせることで、複雑な条件での分析も自由自在に行えるようになります。