VillageSQL is a drop-in replacement for MySQL with extensions.
All examples on this page work on VillageSQL. Install Now →
GROUP BY はグループごとに 1 行を返し、全体の行は返しません。WITH ROLLUP は
その行を追加し、複数の列でグループ化したときはその間の小計も追加します。2 つ目の
クエリを実行して自分で数を足し合わせる手間を省きます。
始める前に、mysql -u root -p sakila でクライアントを開いてください。
WITH ROLLUP の仕組み
GROUPING_COLUMN をグループを定義する列に、TABLE_NAME をテーブルに、
AGGREGATE_FUNCTION(COLUMN_NAME) をグループごとに計算するものに置き換えます。
WITH ROLLUP は GROUP BY 句の末尾に置きます。
サーバーは通常のグループを返し、次に、あるグループ化列を脇に置いてその集約が
全体を対象とする追加の行を返します。脇に置いた列には NULL を入れるので、それで
それらの行を見分けられます。
例
- 合計行を追加する
- 小計も
2 つの列でグループ化すると、1 番目の列の値ごとの小計と、次に総合計が得られます。
G / NULL / 3 は、すべての料金にわたる G
の小計です。NULL / NULL / 10 は総合計で、185 分の映画が 10 本あることと
一致します。
ロールアップの行は、一番下にまとめられるのではなく、それが要約するグループの
後に続くため、結果は上から下へレポートとして読めます。
ロールアップの NULL を本物の NULL と見分ける
ロールアップの行の NULL は「この列のすべての値」を意味します。データ内の NULL は「値が記録されていない」を意味します。両者は同じように表示されるため、NULL になりうる列では、見ただけでは 2 つを区別できません。GROUPING() がこの問いに直接答えます。その行でその列が脇に置かれたときは 1 を、
それ以外は 0 を返します。
rating が NULL になることはないため、ここでは 2 つの問いの答えは
同じです。実際に NULL を保持する列では、rating IS NULL のテストは両方の種類の
行を捕まえ、GROUPING(rating) = 1 はロールアップだけを捕まえます。
ORDER BY は合計を動かし、並び順を変える
上の例にORDER BY がないのは意図的です。WITH ROLLUP は各ロールアップ行を
それが要約するグループの直下に置き、並べ替えはその配置を捨ててしまいます。
ENUM の宣言順ではなくアルファベット順で出てきました。ロールアップ
結果の並べ替えはテキストとして並べ替えるためです。
ですから、どちらが欲しいかを決めてください。グループの下に小計が並ぶレポート
として読むには ORDER BY を付けず、付けるなら、ロールアップの行が並べ替えに
よって置かれる場所に落ち着くことを受け入れます。
ロールアップの行にラベルを付ける
NULL の列はレポートに欲しいものではありません。COALESCE は NULL でない最初の
引数を返すため、代わりにそこに言葉を入れます。
rating が NULL になることが
ないからにすぎません。NULL になりうる列では、COALESCE は本物の欠損値に合計の
ラベルを付けてしまうため、代わりにテストで GROUPING() を使ってください。
まとめ
- 小計と合計の行を得るには、
GROUP BYの末尾にWITH ROLLUPを追加します。 - グループ化列の NULL は「この列のすべての値」として読みます。
- 複数の列でグループ化すると、先行する各列の値ごとに小計が得られると考えてください。
- ロールアップの行とデータが NULL の行を見分けるには
GROUPING(column)を使います。 ORDER BYはロールアップの行を動かし、ENUMをテキストとして並べ替えると考えてください。
関連項目
- GROUP BY — これが合計を追加するグループ
- 集計関数 — 合計されるもの
- IS NULL — その列の NULL が持ちうるもう 1 つの意味
- MySQL の GROUP BY のパフォーマンス — 大規模なグループ化のコスト