小計と総合計を、1つのクエリで出す
ROLLUP と CUBE は、小計と総合計を1つの SQL でまとめて出す、GROUP BY の拡張です。
報告書の表の下に付く「小計」や「合計」の行を、手で足さずに出せます。
さらに FILTER を使うと、商品を横に並べた表も作れます。
このレッスンのゴール
メモ
1つのクエリで、いくつかの段階の合計を出せる。
重要な言葉
| ことば | いみ | れい |
|---|---|---|
| 小計 | 1つのグループだけの合計 | 東日本の合計 |
| 総合計 | 全部の行の合計 | |
| ROLLUP | 左の列から順に小計を作り、最後に総合計を付ける指定 | |
| CUBE | 列のすべての組み合わせの合計を作る指定 | |
| FILTER | 集計関数に、条件に合う行だけを渡す書き方 | |
| ピボット | 縦に並んだ種類を、横の列に並べ替えた表 |
学生が入力するセルは、このプレビューでは空白です。
ROLLUP は、小計と総合計を付けてくれる
group by rollup (region, product) と書くと、3つの段階の合計が出ます。地域と商品の組み合わせ、地域ごとの小計、そして総合計です。
合計の行では、まとめた列が NULL になります。NULL は「その列について全部を足した」という印です。
例: rollup の結果
| region | product | total | 何の合計か |
|---|---|---|---|
| 東日本 | 弁当 | 420000 | 東日本の弁当 |
| 東日本 | NULL | 660000 | 東日本の小計 |
| 西日本 | NULL | 670000 | 西日本の小計 |
| NULL | NULL | 1330000 | 総合計 |
学生が入力するセルは、このプレビューでは空白です。
試す: 小計と総合計
-- 地域と商品ごとの売上に、地域の小計と総合計を付けます。
select region, product, sum(amount) as total
from region_sales
group by rollup (region, product)
order by region nulls last, product nulls last;
-- 結果の NULL は、「その列についての合計」を表します。
CUBE は、すべての組み合わせの合計を出す
rollup は左の列から順に小計を作ります。cube は、商品ごとの合計も作ります。地域の組み合わせが全部そろいます。
grouping(列) は、その行が、その列についての合計なら 1 を返します。データに本物の NULL があっても、これで見分けられます。
試す: cube と grouping
-- cube は、列のすべての組み合わせの合計を出します。
-- grouping は、その行が合計の行なら 1 を返します。
select region, product, sum(amount) as total,
grouping(region) as g_region,
grouping(product) as g_product
from region_sales
group by cube (region, product)
order by region nulls last, product nulls last;
例: rollup と cube の違い
| 指定 | 出る段階の数(列が2つ) | 出る合計 |
|---|---|---|
| group by region, product | 1 | 地域と商品の組み合わせだけ |
| group by rollup (region, product) | 3 | 組み合わせ、地域の小計、総合計 |
| group by cube (region, product) | 4 | 組み合わせ、地域の小計、商品の小計、総合計 |
学生が入力するセルは、このプレビューでは空白です。
FILTER で、条件に合う行だけを足す
sum(amount) filter (where product = '弁当') は、弁当の行だけを足します。列ごとに条件を変えて並べると、ピボットの表になります。
種類が少ないときは、この手作りの形が一番分かりやすいです。
試す: 商品を横に並べる
-- filter を使って、商品を横に並べた表を手で作ります。
select region,
sum(amount) filter (where product = '弁当') as bento,
sum(amount) filter (where product = '飲み物') as drinks,
sum(amount) as total
from region_sales
group by region
order by region;
よくある間違い
注意
結果の NULL を、データが欠けているのだと読み違えることがあります。本物の NULL が表にあるときは、grouping() で合計の行を見分けましょう。
さらに挑戦
rollup (area, channel) と rollup (channel, area) は、同じ結果になりますか。小計の行がどう変わるかを、考えてから実行して確かめましょう。
そのあと、NULL の代わりに「全体」という文字を表示するには、coalesce をどう使えばよいか考えてください。