件数制限の書き方 - 件数制限の方言 (LIMIT / TOP / FETCH)
SELECT の返却行数を制限する書き方は RDBMS ごとに異なる。LIMIT / TOP / FETCH FIRST の違いと移植のコツを解説
概念図
構文
sql
SELECT ... LIMIT n / SELECT TOP n ... / SELECT ... FETCH FIRST n ROWS ONLYサンプル
3 通りの書き方で先頭 10 行 (+20 行スキップ) を取得する例
sql
-- PostgreSQL / MySQL / SQLite
SELECT * FROM products ORDER BY id LIMIT 10 OFFSET 20;
-- SQL Server
SELECT TOP 10 * FROM products ORDER BY id;
-- ANSI 標準 (PostgreSQL / SQL Server / Oracle 12c+ が対応)
SELECT * FROM products
ORDER BY id
OFFSET 20 ROWS FETCH FIRST 10 ROWS ONLY;件数制限はなぜ方言が多いのか
SQL 標準では元々「先頭 N 行だけ取る」構文が定義されていませんでした。そのため各 RDBMS が独自に拡張した結果、LIMIT、TOP、ROWNUM など記法が分かれました。
SQL:2008 でようやく OFFSET ... FETCH FIRST n ROWS ONLY という標準構文が定義され、PostgreSQL / SQL Server / Oracle (12c 以降) が対応しています。しかし現場では歴史的経緯から方言の方が多く使われています。
RDBMS 別比較表
| RDBMS | 基本の書き方 | OFFSET 併用 |
|---|---|---|
| PostgreSQL | LIMIT 10 | LIMIT 10 OFFSET 20 |
| MySQL | LIMIT 10 | LIMIT 20, 10 または LIMIT 10 OFFSET 20 |
| SQLite | LIMIT 10 | LIMIT 10 OFFSET 20 |
| SQL Server | SELECT TOP 10 ... | OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY (2012+) |
| Oracle | FETCH FIRST 10 ROWS ONLY (12c+) / ROWNUM <= 10 (旧) | OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY |
| ANSI 標準 | FETCH FIRST 10 ROWS ONLY | OFFSET 20 ROWS FETCH FIRST 10 ROWS ONLY |
ORDER BY なしの LIMIT は危険
ORDER BY を付けない LIMIT/TOP/FETCH は、どの行が返るかが未定義です。同じクエリでもプランや物理配置が変わると結果が変わります。
ページネーションやランキング等で LIMIT を使う場合は、必ず一意に決まる ORDER BY(タイブレーカーを含む主キー)を付けましょう。
sql
-- 悪い例: 順序が不定
SELECT * FROM orders LIMIT 10;
-- 良い例: 主キーをタイブレーカーに
SELECT * FROM orders
ORDER BY created_at DESC, id DESC
LIMIT 10;移植時の落とし穴
- MySQL の
LIMIT 20, 10: 第1引数が OFFSET、第2が行数。他 RDBMS のLIMIT 10 OFFSET 20とは引数順が真逆なので機械的置換は危険 - SQL Server の TOP に OFFSET は無い: ページネーションしたいなら
OFFSET ... FETCH NEXT(2012 以降) が必須 - Oracle の ROWNUM:
WHERE句で評価されるためORDER BYとの組合せは副問い合わせが必要。12c 以降は FETCH を使うのが素直 - OFFSET が大きいとき: どの RDBMS でも「先頭からスキップ」するので、OFFSET が数万を超えるとキーセットページネーション(
WHERE id > ?)の方が速い
