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文使用して追加するには、通常は以下のように記述します。 ...