MySQL の GROUP BY と HAVING
ここでは MySQL の GROUP BY と HAVING についてご説明します。
サンプルデータベースのテーブルを使いますので、実際にスクリプトを実行してみたい方は、こちら のスクリプトを実行して school_db データベースを作成しておいてください。
GROUP BY でグルーピングして集計する
MySQLの SELECT 文で GROUP BY を使うと、行をグループ化して、そのグループごとに集計したりすることができます。
よく使う基本の SELECT 文の構文は次の通りで、GROUP BY は以下の位置に追加します。
SELECT select_expr
[ FROM table_references ]
[ WHERE where_condition ]
[ GROUP BY {col_name | expr | position} ]
[ HAVING where_condition ]
[ ORDER BY {col_name | expr | position} [ ASC | DESC ] ]
[ LIMIT {[offset,] row_count | row_count OFFSET offset} ];
実際に例をあげて GROUP BY を使いながら、使い方をご説明します。
次のような exam_results テーブルがあります。
この exam_results テーブルから exam_id ごとの最大値 (MAX) 、最小値 (MIN) を取得するには、GROUP BY を使って次のようにできます。
SELECT exam_id,
MIN(score) AS min_score,
MAX(score) AS max_score
FROM exam_results
GROUP BY exam_id;
[実行結果]
exam_id = 1 と 2 の最高点と最低点が取得できていますね。
GROUP BY を使うと SELECT 句に指定できるカラムは GROUP BY で指定したカラムと、集計関数や定数など、グループごとにひとつの値を返すものだけになります。
それ以外のカラムを SELECT 句で指定すると、以下のようにエラーになります。
GROUP BY で複数のカラムを指定してグルーピンクする
GROUP BY の後にはカラム名だけでなく、エイリアス名や、関数や計算された値など指定することができます。
SELECT 句のカラムのインデックスも指定できますが、わかりにくくなるので、あまりおすすめしません。
また GROUP BY で複数のカラムを指定してグルーピンクすることも可能です。
次のような students テーブルがあります。
この students テーブルから誕生日の年ごと、性別ごとでグルーピングした学生の人数を知りたい場合、次のように取得することができます。
GROUP BY の後にまずは birth_year というエイリアス名を指定して誕生年でグルーピングし、次に gender でグルーピングしています。
COUNT(*) で、グループごとのレコードの数を取得できます。
SELECT YEAR(birthday) AS birth_year,
gender,
COUNT(*) AS student_count
FROM students
GROUP BY birth_year,
gender;
[実行結果]
birth_year と gender でグループ化されて、それぞれのグループの学生の数が取得できていますね。
エイリアスを使わず、GROUP BY YEAR(birthday), gender; としても同じ結果になります。
HAVING でグループの条件を指定する
GROUP BY 句と一緒に使われて、結果セットに含めるグループの条件を指定できるのが、HAVING 句です。
先ほど、students テーブルから誕生日の年ごと、性別ごとでグルーピングした学生の人数を取得しました。
その時に学生の数が二人以上存在するグループのみを取得したいような時は、HAVING を使って次のように指定することができます。
SELECT YEAR(birthday) AS birth_year,
gender,
COUNT(*) AS student_count
FROM students
GROUP BY birth_year,
gender
HAVING student_count > 1;
[実行結果]
学生の数が二人以上存在するグループのみが取得できていますね。
こちらもエイリアスを使わず、HAVING COUNT(*) > 1 としても同じ結果になります。
以上、MySQL の GROUP BY と HAVING についてご説明しました。