DevToolBox

SQL GROUP BYORDER BY の順序・使い分け

最終更新日: 2026-04-19公開日: 2026-04-19執筆: DevToolBox編集部

実務で頻出する集計クエリは、句の順序と選択列の制約を押さえれば迷いません。本稿では 書き順・評価順、SELECT に書ける列の制約、 PostgreSQL / MySQL / BigQuery の挙動差をまとめます。

A concise reference for the write-order, evaluation-order, SELECT-column constraints, and dialect differences between GROUP BY and ORDER BY.

SQL Formatter

GROUP BY と ORDER BY を含む長いクエリを自動整形。句ごとに改行されるため、どの列がどこに掛かるかが読み取りやすくなります。

今すぐ試す →

TL;DR

1. 典型クエリ / Canonical query

SELECT user_id,
       COUNT(*)  AS orders,
       SUM(amount) AS total
FROM orders
WHERE created_at >= '2026-01-01'
GROUP BY user_id
HAVING SUM(amount) >= 10000
ORDER BY total DESC
LIMIT 50;

WHERE は行フィルタ、HAVING は集計後フィルタ。混同すると パフォーマンス劣化や意図しない結果になります。

2. SELECT に書ける列の制約 / Column rule

DB / DialectGROUP BY 外の列挙動
PostgreSQL不可column must appear in GROUP BY
MySQL (ONLY_FULL_GROUP_BY on)不可5.7+ デフォルトで有効
MySQL (off)任意行が返る(非決定的)
BigQuery不可ANY_VALUE() で明示
SQL Server / Oracle不可ANSI 準拠

3. ORDER BY の書き方 / ORDER BY tips

4. GROUP BY の落とし穴 / Pitfalls

5. ROLLUP / CUBE で小計・総合計を追加する / Subtotals with ROLLUP and CUBE

グループごとの集計に加えて小計・総合計の行も同時に欲しい場合、GROUP BY ROLLUP(...)が便利です。 毎回UNION ALLで集計行を積み上げる必要がありません。

SELECT region, category, SUM(amount) AS total
FROM sales
GROUP BY ROLLUP(region, category)
ORDER BY region, category;
-- region, category ごとの小計行と、全体の総合計行(両方NULL)が追加される
DB / DialectROLLUPCUBE
PostgreSQL対応対応
MySQL対応(WITH ROLLUP構文)非対応
SQL Server / Oracle対応対応
BigQuery対応対応

MySQLはCUBE非対応な点に注意してください。全次元の組み合わせ集計が必要ならPostgreSQLやBigQueryへの移行、または個別クエリのUNION ALLで代替します。

6. GROUP BYとウィンドウ関数(OVER)の使い分け / GROUP BY vs window functions

GROUP BYは行を1グループ1行に集約しますが、個別の行を保持したまま集計値も 一緒に表示したい場合はウィンドウ関数(OVER句)を使います。

-- GROUP BY: user_idごとに1行に集約される
SELECT user_id, SUM(amount) AS total FROM orders GROUP BY user_id;

-- ウィンドウ関数: 元の行数を保ったまま各行にグループ合計を付与
SELECT order_id, user_id, amount,
       SUM(amount) OVER (PARTITION BY user_id) AS user_total
FROM orders;

「注文明細は残したいが、ユーザーごとの合計も各行に表示したい」といったケースはウィンドウ関数が適しています。

7. パフォーマンス:インデックスとORDER BY / Indexing for GROUP BY + ORDER BY

大きなテーブルでGROUP BYORDER BYを併用すると、ソートのために一時領域へ 書き出す処理(filesortなど)が発生しやすくなります。GROUP BYする列とORDER BYする列を まとめてカバーする複合インデックスを用意しておくと、オプティマイザがソート済みの順序をそのまま 利用できる場合があります。

-- (user_id, created_at) の複合インデックスがあると、
-- 以下のGROUP BY + ORDER BYがソート処理を省略できることがある
CREATE INDEX idx_orders_user_created ON orders (user_id, created_at);

SELECT user_id, COUNT(*) FROM orders GROUP BY user_id ORDER BY user_id;

実際にインデックスが使われているかはEXPLAIN(PostgreSQL/MySQL)や実行計画で確認してください。オプティマイザの挙動はDB・バージョンにより異なります。

8. English summary

In SQL, GROUP BY is always written before ORDER BY. The full evaluation order is FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT, which also explains why HAVING can reference aggregates but WHEREcannot. In all major dialects except MySQL with ONLY_FULL_GROUP_BY disabled, every non-aggregate column in SELECT must appear in GROUP BY. When porting MySQL code, validate against Postgres or BigQuery early.

よくある質問 / FAQ

GROUP BY と ORDER BY はどちらを先に書く?
SQL の構文上は GROUP BY → HAVING → ORDER BY の順。論理的な評価順も同じです。
Which comes first, GROUP BY or ORDER BY?
GROUP BY is written (and evaluated) before ORDER BY. The full clause order is FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT.
SELECT に GROUP BY 外の列を書ける?
PostgreSQL/Oracle/SQL Server は不可(エラー)。MySQL は ONLY_FULL_GROUP_BY を外すと許容するが非推奨。集計関数または GROUP BY 列のみに留めるのが安全です。

関連ツール / Related tools

関連ガイド / Related guides