【MySQL】ROLLUP使用時にORDER BYで結果をソートできる?小計行の並び順を解説
ROLLUPとORDER BYは併用できるのか?
結論から言うと、MySQLではROLLUP修飾子とORDER BY句は互いに排他的な関係にあるため、同じクエリ内で両方を直接組み合わせるのは推奨される使い方ではありません。
ただし、サブクエリ(派生テーブル)を経由すれば、結果のソート自体は可能です。その場合の最大の注意点は、小計行(合計行)も通常のデータ行と一緒にソートされてしまうということです。つまり、指定したソート順によって小計行の表示位置が変わってきます。
ソート順で決まる小計行の位置
ROLLUPで生成された小計行は、昇順(ASC)ソートでは先頭に、降順(DESC)ソートでは末尾に配置されます。これは、小計行のグループキーがNULLとして扱われ、MySQLではNULLが昇順で最初・降順で最後に来るためです。以下の具体例で挙動を確認してみましょう。
降順(DESC)でソートした場合
mysql> Select * from (Select sr, SUM(PRICE) AS PRICE from ratelist GROUP BY sr WITH ROLLUP) AS Price ORDER BY Sr DESC; +------+-------+ | sr | PRICE | +------+-------+ | 5 | 250 | | 4 | 850 | | 3 | 1005 | | 2 | 630 | | 1 | 502 | | NULL | 3237 | +------+-------+ 6 rows in set (0.00 sec)
降順ソートでは、sr = 5 から 1 までのデータ行が並び、NULLの小計行(PRICEの合計 3237)は最後尾に表示されます。
昇順(ASC)でソートした場合
mysql> Select * from (Select sr, SUM(PRICE) AS PRICE from ratelist GROUP BY sr WITH ROLLUP) AS Price ORDER BY Sr ASC; +------+-------+ | sr | PRICE | +------+-------+ | NULL | 3237 | | 1 | 502 | | 2 | 630 | | 3 | 1005 | | 4 | 850 | | 5 | 250 | +------+-------+ 6 rows in set (0.01 sec)
一方、昇順ソートではNULLの小計行が先頭に表示されます。このようにORDER BYを併用すると小計行がデータ行の中に混ざってしまうため、「合計行は常に最後に表示したい」といったレポート出力の要件がある場合には注意が必要です。
バージョンによる違いと実務上のポイント
なお、MySQL 8.0.12以降ではGROUP BY ... WITH ROLLUPとORDER BYを直接組み合わせることが許可されていますが、それ以前のバージョンではエラーとなるため、上記のようにFROM句に派生テーブルを書く方法が定番の回避策となります。
小計行・合計行の位置をより厳密に制御したい場合は、CASE式や IS NULL を活用してNULLを常に末尾へ固定するようなORDER BYの工夫をするか、取得後のデータをアプリケーション側でソート・整形するのも有効な手段です。
-
MySQLで行の値を合計して結果を並べ替えるクエリの書き方
MySQLで行の値を合計し、結果を並べ替える方法テーブル内の同じキーを持つ行の値を合計し、その結果を並べ替えたい場合には、GROUP BY句とORDER BY句を組み合わせて使用します。GROUP BYで対象の列ごとにデータをグループ化し、SUM関数で合計値を算出した後、ORDER BYで並べ替えるという流れになります。ここでは、生徒名と点数が登録されたテーブルを例に、生徒ごとの合計点を降順で取得する手順を解説します。1. サンプルテーブルを作成するまず、CREATE TABLE文でテーブルを作成します。mysql> create table DemoTable1499 &nb
-
MySQLのORDER BY FIELDを使って特定の値を優先し、ID順に並べ替える方法
はじめにMySQLでは、ORDER BY FIELD() を活用することで、特定の値を持つレコードを最優先で表示しつつ、残りのレコードをIdなどの別の列基準で並べ替えることができます。この記事では、実際のサンプルコードを通してその手順をわかりやすく解説します。サンプルテーブルの作成まず、テーブルを作成しましょう。mysql> create table DemoTable -> ( -> Id int, -> Name varchar(20) -> ); Query OK, 0 rows affected (1.78 sec)次に、I