メインコンテンツへスキップ

VillageSQL is a drop-in replacement for MySQL with extensions.

All examples on this page work on VillageSQL. Install Now →
GROUP BY のない集計関数は、テーブル全体を 1 つのグループとして扱い、1 行を 返します。GROUP BY はまず行をグループに分けるため、グループごとに 1 行が得られ ます。「映画は何本あるか」が「レーティングごとに映画は何本あるか」になるのは こうしてです。 始める前に mysql -u root -p sakila でクライアントを開いてください。

GROUP BY の仕組み

GROUPING_COLUMN をその値がグループを定める列に、TABLE_NAME をテーブルに、 AGGREGATE_FUNCTION(COLUMN_NAME) を各グループについて計算したいものに置き換え ます。 サーバーは行を、グループ化列の異なる値ごとに 1 つのバケットに振り分け、各 バケットに対して別々に集計関数を実行します。結果の行数は、異なる値の数と同じ です。 GROUP BY は WHERE の後、ORDER BY の前に置きます。これは結果が定義される 順序でもあります。行をフィルタし、残ったものをグループ化し、それからグループを 並べ替えます。

例

  1. 値ごとに 1 行

rating には 5 つの異なる値があるため 5 グループで、5 つの件数を足すと 1,000 に なります。行はアルファベット順ではなく ENUM の宣言順で出てきます。これは SELECT DISTINCT のレッスンで説明しています。

  1. 2 つの列でグループ化する

2 つの列を指定すると、グループはそれぞれの値ではなく、異なる組み合わせになり ます。
5 つのレーティングかける 3 つの料金で 15 グループです。これは SELECT DISTINCT rating, rental_rate が返すのと同じ形に、各行の件数を付けた ものです。

  1. グループ化の前に行をフィルタする

WHERE が先に実行されるため、件数はそれを通過した行に対するものです。
依然として 5 グループですが、すべて小さくなっています。グループが完全に消えるのは、 WHERE がそのグループの行をすべて取り除いたときだけです。

  1. 計算したものでグループ化する

グループ化列は列である必要はありません。任意の式が使え、エイリアスで名前を付けて それでグループ化できます。
GROUP BY は選択リストのエイリアスを受け入れますが、WHERE は受け入れません。 レポートが月ごとにグループ化されるのはこうしてです。月を計算し、それでグループ化 します。

  1. 結合に対してグループ化する

グループ化が最も役立つのは、行が複数のテーブルから来るときです。これは各顧客の 支払いを数えます。
結合が先に実行されて支払いごとに 1 行を生成し、それからグループ化がそれらの行を 顧客ごとにまとめます。GROUP BY に last_name だけでなく customer_id も入って いるのは、2 人の顧客が同じ姓を共有し得るため、それらを別々に数えたいからです。

選択したすべての列はグループ化されるか集計されなければならない

グループは多数の行です。グループ化列でもなく集計関数の中にもない列を求めるのは、 その多数の行のどれを表示するかをサーバーに尋ねることであり、サーバーに答えは ありません。デフォルトで有効な only_full_group_by 設定が、サーバーに推測では なくそう言わせるものです。
ERROR 1055 は解決できなかった列を名指しします。ここでは title です。出口は 3 つあり、どれが正しいかは意図によります。
  • より細かいグループが欲しかったなら、その列を GROUP BY に追加します。
  • どれか 1 つの値でよいなら、MIN(title) のような集計関数で包みます。
  • 必要なかったなら、選択リストから外します。
only_full_group_by を無効にすると、同じクエリは実行され、サーバーが選んだ プラン次第で任意のタイトルを返します。 MySQL の GROUP BY のパフォーマンスのガイドでは、この 設定と、意図的に任意の行を求める方法である ANY_VALUE() を扱っています。

GROUP BY は順序を約束しない

グループは、サーバーが都合の良いと判断した順序で返ってきます。ここのすべての例に ORDER BY があるのは、LIMIT と同じく、それが順序を固定する 唯一の方法だからです。

まとめ

  • 全体で 1 行ではなく、異なる値ごとに 1 行の結果を得るには GROUP BY を使います。
  • 複数の列を指定すると、異なる組み合わせごとにグループができると考えてください。
  • WHERE はグループ化が起きる前に行をフィルタすると考えてください。
  • ERROR 1055 は、グループ化も集計もされていない列と読んでください。
  • グループの順序が重要なときは ORDER BY を追加します。

関連項目