CodeGym /コース /SQL SELF /データのグループ化(GROUP BY):構文とストラクチャ

データのグループ化(GROUP BY):構文とストラクチャ

SQL SELF
レベル 8 , レッスン 0
使用可能

何千行ものデータを扱ってるとき、どうやって意味を見つける?そこで登場するのがGROUP BY演算子だよ。SQLのオーケストラで指揮者みたいな存在。バラバラなデータをキレイなメロディーに変えてくれる:数えたり、グループ化したり、まとめたり。例えば、各クライアントが何件注文したか、各コースに何人学生がいるか、部署ごとの給料の分布とか知りたい?全部GROUP BYの仕事!今日はこいつと仲良くなって、テーブルから最大限にデータを引き出す方法を見ていこう。

グループ化っていうのは、1つまたは複数のカラムで同じ値を持つ行を論理的なグループにまとめるプロセスだよ。これで、各グループごとに集約関数を使えるようになる。

例えば、社員テーブルがあって、各部署ごとの平均給料を知りたいとする。一つの部署が一つのグループ。SQLはGROUP BYを使って社員テーブルを部署ごとに分けて、各グループにAVG()を適用するんだ。

GROUP BYの構文

SQLでグループ化を使うときの一番大事なルール:GROUP BYを使うなら、集約関数じゃないカラムは全部GROUP BYに書かないとダメ。

構文:

SELECT カラム1, 
       集約関数(カラム2)
FROM テーブル
GROUP BY カラム1;

やることのステップ:

  1. グループ化したいカラムをGROUP BYに指定する。
  2. グループごとに値を計算するために集約関数を使う。
  3. SELECTの中で集約関数じゃないカラムは全部GROUP BYに書く。SQLはこの辺厳しいから、忘れるとエラーで怒られるよ。

例:学生を学部ごとにグループ化

例えば、studentsテーブルがあって、学生のデータが入ってるとする:

id name faculty gpa
1 Alex Lin ComputerSci 3.8
2 Maria Chi Math 3.5
3 Anna Song ComputerSci 4.0
4 Otto Art Math 3.9
5 Liam Park Physics 3.7

今度は、各学部ごとの平均GPAを知りたい。だからGROUP BYを使ったクエリを書くよ:

SELECT faculty, AVG(gpa) AS avg_gpa
FROM students
GROUP BY faculty;

結果:

faculty avg_gpa
ComputerSci 3.9
Math 3.7
Physics 3.7

SQLはまずfacultyカラムの値ごとにデータをグループ分けして、それぞれのグループにAVG()関数を適用したんだ。

GROUP BYの使い方のポイント

  1. SELECT内のカラムの要件

SQLは、SELECTで指定したカラムのうち、SUM()COUNT()みたいな集約関数を使ってないカラムは全部GROUP BYに書くように要求してくる。グループ化しないと、どの値を出せばいいかSQLが分からないからだよ。

例えば、次のクエリを実行するとエラーになる:

SELECT name, AVG(gpa)
FROM students
GROUP BY faculty;

エラー:nameカラムがGROUP BYに指定されてない。これを直すには、nameGROUP BYに追加する:

SELECT name, AVG(gpa)
FROM students
GROUP BY faculty, name;

でもこれだと、今度は個々の学生ごとにグループ化されちゃうから、最初に欲しかった結果とは違うよね。

  1. 複数カラムでのグループ化

1つだけじゃなくて、複数のカラムでグループ化もできる。例えば、学部だけじゃなくて名前でもグループ化したいなら、GROUP BYに2つ目のカラムを追加するだけ:

SELECT faculty, name, AVG(gpa) AS avg_gpa
FROM students
GROUP BY faculty, name;

元のテーブル:

id name faculty gpa
1 Alex Lin ComputerSci 3.8
2 Maria Chi Math 3.5
3 Anna Song ComputerSci 4.0
4 Otto Art Math 3.9
5 Liam Park Physics 3.7

結果:

faculty name avg_gpa
ComputerSci Alex Lin 3.8
ComputerSci Anna Song 4.0
Math Maria Chi 3.5
Math Otto Art 3.9
Physics Liam Park 3.7
  1. 複数の集約関数を使ったグループ化

1つの関数だけにしないでOK!例えば、学部ごとの学生数と平均GPAを両方出したい場合:

SELECT faculty,
       COUNT(*) AS student_count, 
       AVG(gpa) AS avg_gpa
FROM students
GROUP BY faculty;

元のテーブル:

id name faculty gpa
1 Alex Lin ComputerSci 3.8
2 Maria Chi Math 3.5
3 Anna Song ComputerSci 4.0
4 Otto Art Math 3.9
5 Liam Park Physics 3.7

結果:

faculty student_count avg_gpa
ComputerSci 2 3.9
Math 2 3.7
Physics 1 3.7

SQLでのグループ化の特徴:選べるもの・選べないもの

グループ化クエリは書くの簡単だけど、たぶん半分くらいは最初うまく動かない。グループ化は、普段自分の頭でやってるのとちょっと違う感じで動くんだ。

SQLクエリにGROUP BYがあるなら、結果のカラムは全部「計算された式」だと思って。SELECTのカラムは2種類だけ:

  • グループのカラムを使って集約関数で計算されるやつ。
  • GROUP BYで指定したカラム(これでグループ化されてるやつ)。

もしstudentsテーブルでGROUP BYクエリをやるなら、結果テーブルに個々の学生は出せない!出せるのは平均身長、平均体重、平均GPAみたいなやつ。こういうコードは動かない:

SELECT faculty, name
FROM students
GROUP BY faculty;

なんでか、ちょっと考えてみよう。

GROUP BY faculty演算子は、studentsテーブルの学生をfacultyが同じグループに分ける。グループ内の全員が同じfacultyだから、グループにはfaculty属性があるって言える。でもnameはみんな違う。だからグループにはname属性がないんだ。

GROUP BY faculty, gender演算子は、studentsテーブルの学生をfacultygenderが同じグループに分ける。だからグループ内の全員が同じfacultygenderを持つ。つまりグループにはfacultygender属性がある。でもグループに共通のnameはやっぱりない。

こう書くのはOK:

SELECT faculty, gender
FROM students
GROUP BY faculty, gender;

こんな感じでもOK:

SELECT
    faculty, 
    gender, 
    AVG(age) as group_avg_age,  -- groupのage値から計算される値
    MAX(high) as group_high     -- groupのhigh値から計算される値
FROM students
GROUP BY faculty, gender;

でも、単にagehighSELECTで使うのはこの場合ダメ。

GROUP BYでよくあるミス

GROUP BYでクエリを書き始めたら、こんな落とし穴に注意してね:

  1. SELECTに全部のカラムを書いてない。 集約じゃないカラムは全部GROUP BYに書くのを忘れずに。そうしないとSQLはどう表示していいか分からない。

  2. NULLでグループ化。 NULL値は別グループとして扱われる。カラムにNULLがあると、SQLはNULL用のグループを作るよ。

  3. グループが細かすぎる。 GROUP BYにカラムを入れすぎると、細かすぎる結果になって分析しにくくなることも。

これでGROUP BYを使ってデータを効率よくグループ化できるようになったね。SQLで一番強力なツールの一つで、集約データを簡単に扱ったり、構造化されたレポートを作れるよ。次はHAVINGを使った追加フィルターのやり方も見ていこう!

コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION