WITH ROLLUP を使って小計と総合計を取得する [SQLServer, MySQL]

SQLで集計をしていると、GROUP BYでグループ化して集計した明細レコードと一緒に、小計や合計のレコードを取得したい場合があります。
そこで今回は、1回のSQLでグループ化したデータの明細と一緒に、小計レコードと合計レコードを取得する方法を紹介します。

小計と合計の取得

小計レコードと合計レコードを明細レコードと一緒に取得する際はGROUP BY句で「WITH ROLLUP」修飾子を使用します。
例えば、PCで使用されているWebブラウザーを国ごとに集計するSQLなら以下のようになります。

取得結果

Webブラウザー国別使用数集計サンプル1

GROUP BY句でブラウザーと国でグループ化してCOUNT関数で件数を取得しています。
このSQLのGROUP BY句にWITH ROLLUP修飾子を使ってブラウザーごとの小計と全体の合計レコードを追加します。

取得結果

Webブラウザー国別使用数集計サンプル2

国ごとの小計と全体の合計レコードを追加するなら以下のようになります。

取得結果

Webブラウザー国別使用数集計サンプル3

小計、合計取得サンプルSQL

より具体的な例としてデータを集計するためのテーブルを作成し、小計と合計を取得するサンプル用のデータを登録してSQLを作成します。
サンプルのSQLでは学生の成績を科目と性別ごとに集計し、科目ごとの小計レコードと、全データの合計レコードを合わせて取得します。

サンプルSQLで使用するテーブル

テーブルは次の4つのテーブルを作成します。

  1. 性別マスタテーブル
  2. 科目マスタテーブル
  3. 学生マスタテーブル
  4. 成績テーブル

性別マスタと科目マスタはコードと名称を保持します。
学生マスタは学生の番号と氏名、性別(性別コード)を保持します。
成績テーブルは学生(学生番号)と科目(科目コード)ごとの成績(素点)を保持します。
各テーブルの定義は以下になります。

性別マスタテーブル
列名 データ型 PK
性別コード nvarchar(1)
性別名称 nvarchar(1)
科目マスタテーブル
列名 データ型 PK
科目コード nvarchar(3)
科目名称 nvarchar(10)
学生マスタテーブル
列名 データ型 PK
学生番号 int
氏名 nvarchar(20)
性別コード nvarchar(1)
成績テーブル
列名 データ型 PK
学生番号 int
科目コード nvarchar(5)
素点 int

テーブルの作成とデータの登録

テーブルのCREATE文とデータを投入するINSERT文です。

まずは成績情報を科目と性別でグループ化します。

実行結果

科目、性別ごとの点数集計

これで科目と性別ごとの点数の集計(SUM)を取得できました。

次に科目ごとの小計レコードと合計レコードを取得するので、GROUP BY句の性別コードの後にWITH ROLLUP修飾子を付けます。

実行結果

科目、性別ごとの点数集計 + 科目ごとの小計 + 全体の合計

これで科目と性別ごとの集計レコードと科目ごとに集計した小計レコード(男女の合計レコード)と全体の合計レコードが取得できました。

このままだと科目コード、性別コード、集計した点数(素点)の3列しかないので、分かりやすくするために科目名称と性別名称を追加します。

実行結果

集計データにマスタテーブルを結合して名称を取得

最後に小計レコードと合計レコードの科目と性別がNULLになっているので変換します。

実行結果

小計レコードと合計レコードの文字列を変換

小計レコードと合計レコードをCASE式でIS NULLを使用して判断していますが、GROUPING関数が用意されているデータベースであれば、置き換えることで同じ結果を得ることもできます。

関連情報補足

本記事のINSERT INTOステートメントは、複数のレコードを1回のSQLで一括挿入する形式で記述しています。
1回のINSERTで複数行のレコードをテーブルに挿入する方法については、以下の記事を参照してください。

1回のINSERT(インサートSQL)で複数行のレコードを一括挿入(追加)する
SQLServerやMySQLなどのデータベースで、テーブルにレコードをINSERT文使用して追加するには、通常は以下のように記述します。 ...