SQLで「先頭の5件だけ取得したい」「11件目から20件目までを表示したい」といった場面は頻繁にあります。Webアプリケーションのページネーション(ページ送り)や、ランキングの上位N件表示など、取得件数を制限する操作はデータベース操作の基本です。
SQLでは LIMIT句 を使うことで取得する行数を制限できます。ただし、LIMIT句はSQL標準ではなく、RDBMS(データベース製品)によって構文が異なります。この記事では、LIMIT句の基本から OFFSET によるページネーション、Oracle・SQL Server・MySQL・PostgreSQL の構文比較、大量データでのパフォーマンス対策まで体系的に解説します。
この記事で学べること
- LIMIT句の基本構文と取得件数の指定方法
- ORDER BY + LIMIT で上位N件を取得する方法
- LIMIT + OFFSET でページネーションを実装する方法
- MySQL / PostgreSQL / Oracle / SQL Server の構文比較
- OFFSETを使ったページネーションの実装パターン
- 大きいOFFSETが遅くなる理由とカーソルベースの対策
- 最新N件・TOP10・ランダム取得などの実務パターン
- ORDER BYなしのLIMITやOFFSETのずれなど、よくあるミス
サンプルデータの準備
この記事では以下の products テーブルを使って解説します。
▶ CREATE TABLE + INSERT文(クリックで展開)
CREATE TABLE products (
id INT PRIMARY KEY,
name VARCHAR(50),
category VARCHAR(20),
price INT,
stock INT,
created_at DATE
);
INSERT INTO products VALUES
(1, 'ノートPC', '電子機器', 89000, 15, '2024-01-10'),
(2, 'マウス', '周辺機器', 3500, 120, '2024-01-15'),
(3, 'キーボード', '周辺機器', 8900, 85, '2024-02-01'),
(4, 'モニター', '電子機器', 45000, 30, '2024-02-10'),
(5, 'USBメモリ', '周辺機器', 1200, 200, '2024-02-20'),
(6, 'Webカメラ', '周辺機器', 5600, 60, '2024-03-01'),
(7, 'タブレット', '電子機器', 55000, 25, '2024-03-15'),
(8, 'ヘッドセット', '周辺機器', 12000, 45, '2024-04-01'),
(9, '外付けSSD', '周辺機器', 9800, 70, '2024-04-10'),
(10, 'デスクトップPC', '電子機器', 120000, 10, '2024-05-01'),
(11, 'スピーカー', '周辺機器', 7800, 55, '2024-05-15'),
(12, 'プリンター', '電子機器', 35000, 20, '2024-06-01');
| id |
name |
category |
price |
stock |
created_at |
| 1 |
ノートPC |
電子機器 |
89,000 |
15 |
2024-01-10 |
| 2 |
マウス |
周辺機器 |
3,500 |
120 |
2024-01-15 |
| 3 |
キーボード |
周辺機器 |
8,900 |
85 |
2024-02-01 |
| 4 |
モニター |
電子機器 |
45,000 |
30 |
2024-02-10 |
| 5 |
USBメモリ |
周辺機器 |
1,200 |
200 |
2024-02-20 |
| 6 |
Webカメラ |
周辺機器 |
5,600 |
60 |
2024-03-01 |
| 7 |
タブレット |
電子機器 |
55,000 |
25 |
2024-03-15 |
| 8 |
ヘッドセット |
周辺機器 |
12,000 |
45 |
2024-04-01 |
| 9 |
外付けSSD |
周辺機器 |
9,800 |
70 |
2024-04-10 |
| 10 |
デスクトップPC |
電子機器 |
120,000 |
10 |
2024-05-01 |
| 11 |
スピーカー |
周辺機器 |
7,800 |
55 |
2024-05-15 |
| 12 |
プリンター |
電子機器 |
35,000 |
20 |
2024-06-01 |
LIMIT句の基本構文
取得件数の指定
LIMIT句はSELECT文の末尾に記述し、取得する行数の上限を指定します。
LIMIT句の基本構文
SELECT 列名1, 列名2, ...
FROM テーブル名
LIMIT 取得件数;
productsテーブルから先頭の5件だけを取得してみましょう。
先頭5件を取得
SELECT id, name, price
FROM products
LIMIT 5;
| id |
name |
price |
| 1 |
ノートPC |
89,000 |
| 2 |
マウス |
3,500 |
| 3 |
キーボード |
8,900 |
| 4 |
モニター |
45,000 |
| 5 |
USBメモリ |
1,200 |
注意
ORDER BYを指定しない場合、どの行が返されるかは不定です。テーブルの物理的な格納順に依存するため、INSERT順と同じとは限りません。確実に「先頭N件」を取得したい場合は、必ずORDER BYと組み合わせてください。
ORDER BY + LIMIT の組み合わせ(TOP N)
実務では ORDER BY で並び替えてから LIMIT で件数を制限する のが基本パターンです。「価格が高い順に3件」「最新の5件」といった上位N件の取得ができます。
価格が高い順に上位3件を取得
SELECT id, name, price
FROM products
ORDER BY price DESC
LIMIT 3;
| id |
name |
price |
| 10 |
デスクトップPC |
120,000 |
| 1 |
ノートPC |
89,000 |
| 7 |
タブレット |
55,000 |
SQLの記述順と処理順序を確認しておきましょう。
SQLの処理順序
1. FROM(テーブルの選択)
2. WHERE(行の絞り込み)
3. GROUP BY(グループ化)
4. HAVING(グループの絞り込み)
5. SELECT(列の選択)
6. ORDER BY(並び替え)
7. LIMIT(件数制限)← 最後に実行される
LIMIT句は最後に処理されるため、WHERE句で絞り込んだ結果やORDER BYで並び替えた結果に対して件数制限が適用されます。
LIMIT + OFFSET でページネーション
OFFSET句を組み合わせると、先頭から指定した行数をスキップしてデータを取得できます。これがページネーション(ページ送り)の基本です。
LIMIT + OFFSET の構文
SELECT 列名1, 列名2, ...
FROM テーブル名
ORDER BY 列名
LIMIT 取得件数 OFFSET スキップ件数;
-- 省略記法(MySQL)
SELECT 列名 FROM テーブル名
LIMIT スキップ件数, 取得件数;
例えば、価格の安い順に並べて「4件目から3件」を取得する場合はこうなります。
4件目から3件取得(OFFSETは0始まり)
SELECT id, name, price
FROM products
ORDER BY price ASC
LIMIT 3 OFFSET 3;
| id |
name |
price |
| 6 |
Webカメラ |
5,600 |
| 11 |
スピーカー |
7,800 |
| 3 |
キーボード |
8,900 |
OFFSETは 0始まり です。OFFSET 0 は先頭から、OFFSET 3 は4番目の行からデータを取得します。次の図でイメージを確認しましょう。
OFFSET のイメージ
全12件のデータ(価格昇順):
[1] USBメモリ 1,200 ← OFFSET 0(ここから)
[2] マウス 3,500
[3] Webカメラ 5,600 ← LIMIT 3 OFFSET 0 はここまで
[4] スピーカー 7,800 ← OFFSET 3(ここから)
[5] キーボード 8,900
[6] 外付けSSD 9,800 ← LIMIT 3 OFFSET 3 はここまで
[7] ヘッドセット 12,000 ← OFFSET 6(ここから)
…
RDBMS別の件数制限構文
LIMIT句は SQL標準の構文ではありません。MySQLとPostgreSQLではLIMITが使えますが、OracleやSQL Serverでは別の構文を使います。ここでは主要なRDBMSの構文を比較します。
MySQL / PostgreSQL:LIMIT … OFFSET
MySQLとPostgreSQLは同じ構文で LIMIT + OFFSET が使えます。
MySQL / PostgreSQL
-- 基本(先頭N件)
SELECT * FROM products LIMIT 10;
-- OFFSET付き
SELECT * FROM products LIMIT 10 OFFSET 20;
-- MySQL省略記法(OFFSET, LIMITの順に注意)
SELECT * FROM products LIMIT 20, 10;
MySQL省略記法の注意
LIMIT 20, 10 と書くと「20件スキップして10件取得」です。第1引数がOFFSET、第2引数がLIMITで、LIMIT 10 OFFSET 20 と順序が逆になります。混乱しやすいので、LIMIT … OFFSET … 形式を推奨します。
Oracle:FETCH FIRST … ROWS ONLY / ROWNUM
Oracleでは 12c以降 で FETCH FIRST 構文(SQL:2008標準準拠)が使えます。それ以前のバージョンではROWNUMを使います。
Oracle 12c以降(FETCH FIRST)
-- 先頭N件
SELECT * FROM products
ORDER BY price DESC
FETCH FIRST 10 ROWS ONLY;
-- OFFSET付き
SELECT * FROM products
ORDER BY price DESC
OFFSET 20 ROWS
FETCH NEXT 10 ROWS ONLY;
Oracle 11g以前(ROWNUM)
-- 先頭N件(サブクエリが必要)
SELECT * FROM (
SELECT * FROM products
ORDER BY price DESC
)
WHERE ROWNUM <= 10;
-- OFFSET付き(二重サブクエリ)
SELECT * FROM (
SELECT a.*, ROWNUM AS rn FROM (
SELECT * FROM products
ORDER BY price DESC
) a WHERE ROWNUM <= 30
)
WHERE rn > 20;
SQL Server:TOP / OFFSET-FETCH
SQL Serverでは TOP で先頭N件を取得し、OFFSET-FETCH(2012以降)でページネーションを行います。
SQL Server
-- TOP(先頭N件)
SELECT TOP 10 * FROM products
ORDER BY price DESC;
-- OFFSET-FETCH(ページネーション、2012以降)
SELECT * FROM products
ORDER BY price DESC
OFFSET 20 ROWS
FETCH NEXT 10 ROWS ONLY;
RDBMS別構文の比較表
各RDBMSの件数制限構文をまとめます。
| 機能 |
MySQL |
PostgreSQL |
Oracle 12c+ |
SQL Server 2012+ |
| 先頭N件 |
LIMIT N |
LIMIT N |
FETCH FIRST N ROWS ONLY |
TOP N |
| OFFSET付き |
LIMIT N OFFSET M |
LIMIT N OFFSET M |
OFFSET M ROWS FETCH NEXT N ROWS ONLY |
OFFSET M ROWS FETCH NEXT N ROWS ONLY |
| ORDER BY必須 |
任意 |
任意 |
OFFSET使用時は必須 |
OFFSET使用時は必須 |
| SQL標準準拠 |
非標準 |
非標準 |
SQL:2008準拠 |
SQL:2008準拠 |
ポイント
Oracle 12c+ と SQL Server 2012+ の OFFSET ... FETCH 構文は同じ書き方です。これは SQL:2008標準 に準拠した構文で、将来的にはこの書き方が主流になると予想されます。PostgreSQLもこの構文をサポートしています。
OFFSETを使ったページネーション
Webアプリケーションで最もよく使われるLIMIT句の活用例がページネーション(ページ送り)です。1ページに表示する件数を決めて、ページ番号に応じてOFFSETを計算します。
基本のページネーション実装
1ページあたり5件表示する場合の各ページのSQLを見てみましょう。
ページネーションの各ページ
-- 1ページ目(1〜5件目)
SELECT * FROM products
ORDER BY id
LIMIT 5 OFFSET 0;
-- 2ページ目(6〜10件目)
SELECT * FROM products
ORDER BY id
LIMIT 5 OFFSET 5;
-- 3ページ目(11〜12件目)
SELECT * FROM products
ORDER BY id
LIMIT 5 OFFSET 10;
3ページ目はデータが2件しかないため、2件だけが返されます。LIMITで指定した件数よりデータが少ない場合は、存在する分だけが返されます(エラーにはなりません)。
ページ番号からOFFSETを計算する方法
ページネーションでは、ページ番号(page)と1ページあたりの表示件数(per_page)からOFFSETを算出します。計算式は次の通りです。
OFFSET の計算式
OFFSET = (ページ番号 – 1) × 1ページあたりの件数
| ページ番号 |
計算式 |
OFFSET値 |
取得範囲 |
| 1 |
(1-1) x 5 |
0 |
1〜5件目 |
| 2 |
(2-1) x 5 |
5 |
6〜10件目 |
| 3 |
(3-1) x 5 |
10 |
11〜15件目 |
| N |
(N-1) x 5 |
(N-1) x 5 |
… |
アプリケーション側(PHP、Python、Javaなど)のコードでは、次のように実装します。
アプリケーション側の実装例(疑似コード)
-- ページ番号: :page(1始まり)
-- 表示件数: :per_page
SELECT * FROM products
ORDER BY id
LIMIT :per_page
OFFSET (:page - 1) * :per_page;
総件数の取得(COUNT + LIMIT)
ページネーションUIを構築するには、総件数(総ページ数の算出用)と該当ページのデータの両方が必要です。通常は2つのクエリを実行します。
総件数とデータの取得
-- 1. 総件数を取得
SELECT COUNT(*) AS total_count
FROM products;
-- 2. 該当ページのデータを取得
SELECT * FROM products
ORDER BY id
LIMIT 5 OFFSET 0;
-- 総ページ数 = CEIL(total_count / per_page)
-- 例: CEIL(12 / 5) = 3ページ
ポイント
WHERE句で絞り込みを行っている場合は、COUNT(*)にも同じWHERE条件を付ける必要があります。条件なしのCOUNT(*)では正しい総ページ数が計算できません。
WHERE条件付きの場合
-- 総件数(条件付き)
SELECT COUNT(*) AS total_count
FROM products
WHERE category = '周辺機器';
-- データ取得(同じ条件)
SELECT * FROM products
WHERE category = '周辺機器'
ORDER BY id
LIMIT 5 OFFSET 0;
パフォーマンスの注意点
LIMIT + OFFSET によるページネーションはシンプルで実装しやすい反面、データ量が増えるとパフォーマンスが大幅に低下する場合があります。ここでは原因と対策を解説します。
大きいOFFSETが遅い理由
例えば10万件のテーブルで LIMIT 10 OFFSET 99990(最後のページ)を実行すると、データベースは内部的に100,000行を読み取り、そのうち99,990行を捨て、残りの10行だけを返すという処理を行います。
OFFSETが大きいと遅い
-- OFFSET 0: 高速(先頭10件だけ読む)
SELECT * FROM large_table ORDER BY id LIMIT 10 OFFSET 0;
-- OFFSET 99990: 低速(100,000行を読んで99,990行捨てる)
SELECT * FROM large_table ORDER BY id LIMIT 10 OFFSET 99990;
つまり、OFFSETの値が大きいほど処理が遅くなるのです。これはページ番号が後ろになるほど体感速度が落ちる原因です。
| OFFSET値 |
内部で読む行数 |
返す行数 |
速度 |
| 0 |
10 |
10 |
高速 |
| 1,000 |
1,010 |
10 |
普通 |
| 10,000 |
10,010 |
10 |
やや遅い |
| 99,990 |
100,000 |
10 |
非常に遅い |
カーソルベースのページネーション(WHERE id > 最後のID)
OFFSETの問題を解決する方法が カーソルベースのページネーション(keyset pagination)です。前のページの最後のレコードのIDを基準にして次のページを取得します。
カーソルベースのページネーション
-- 1ページ目(通常通り)
SELECT * FROM products
ORDER BY id
LIMIT 5;
-- 結果: id = 1, 2, 3, 4, 5(最後のIDは5)
-- 2ページ目(id > 5 で絞り込み)
SELECT * FROM products
WHERE id > 5
ORDER BY id
LIMIT 5;
-- 結果: id = 6, 7, 8, 9, 10(最後のIDは10)
-- 3ページ目(id > 10 で絞り込み)
SELECT * FROM products
WHERE id > 10
ORDER BY id
LIMIT 5;
この方法では、何ページ目であっても常にインデックスを使って高速にデータを取得できます。OFFSETのように前の行を読み飛ばす必要がありません。
インデックスの活用
LIMIT + ORDER BYのパフォーマンスを最大化するには、ORDER BY で指定するカラムにインデックスを作成することが重要です。
インデックスの作成
-- ORDER BY + LIMITで使うカラムにインデックスを作成
CREATE INDEX idx_products_price ON products(price);
-- 複合インデックス(WHERE + ORDER BY + LIMITの場合)
CREATE INDEX idx_products_cat_price
ON products(category, price);
インデックスがあれば、データベースはテーブル全体をスキャンせずに必要な行だけを効率的に取得できます。特にORDER BY + LIMITの組み合わせでは、インデックスの有無で実行速度が大きく変わります。
OFFSET vs カーソルベースの比較表
| 比較項目 |
OFFSET方式 |
カーソルベース方式 |
| 実装の簡単さ |
簡単 |
やや複雑 |
| 大量データの速度 |
OFFSETが大きいと遅い |
常に高速 |
| 任意ページへのジャンプ |
可能 |
不可(順次のみ) |
| データ追加・削除時 |
重複・欠落の可能性あり |
一貫性が保たれる |
| 適用場面 |
管理画面、少量データ |
SNSフィード、無限スクロール |
使い分けの目安
数千件程度のデータならOFFSET方式で十分です。数万件以上になる場合や、TwitterやInstagramのような無限スクロールUIを実装する場合は、カーソルベース方式を検討してください。
実務でよく使うパターン
ここからは、実際の開発現場でよく使われるLIMIT句の活用パターンを紹介します。
最新N件の取得
新着情報やお知らせの表示で最も多いパターンです。日付の降順(新しい順)に並べてLIMITで件数を制限します。
最新5件の商品を取得
SELECT id, name, price, created_at
FROM products
ORDER BY created_at DESC
LIMIT 5;
| id |
name |
price |
created_at |
| 12 |
プリンター |
35,000 |
2024-06-01 |
| 11 |
スピーカー |
7,800 |
2024-05-15 |
| 10 |
デスクトップPC |
120,000 |
2024-05-01 |
| 9 |
外付けSSD |
9,800 |
2024-04-10 |
| 8 |
ヘッドセット |
12,000 |
2024-04-01 |
売上TOP10(ランキング)
集計関数と組み合わせてランキングを作成する例です。GROUP BYで集計した結果にORDER BY + LIMITを適用します。
カテゴリ別の在庫数ランキング
SELECT
category,
SUM(stock) AS total_stock,
COUNT(*) AS product_count
FROM products
GROUP BY category
ORDER BY total_stock DESC
LIMIT 3;
| category |
total_stock |
product_count |
| 周辺機器 |
635 |
7 |
| 電子機器 |
100 |
5 |
ランダムに1件取得(ORDER BY RAND())
ランダムな1件を取得するには ORDER BY RAND() と LIMIT 1 を組み合わせます。
ランダムに1件取得(MySQL)
SELECT * FROM products
ORDER BY RAND()
LIMIT 1;
ORDER BY RAND() の注意点
ORDER BY RAND() は全行にランダムな値を割り当ててソートするため、大量データでは非常に遅くなります。数万件以上のテーブルでは、以下のようにIDの範囲からランダムに取得する方が高速です。
高速なランダム取得(代替方法)
-- IDが連番の場合の高速な方法
SELECT * FROM products
WHERE id >= (
SELECT FLOOR(
RAND() * (SELECT MAX(id) FROM products)
) + 1
)
ORDER BY id
LIMIT 1;
サブクエリでのLIMIT
サブクエリ(副問合せ)の中でLIMITを使うことで、「最も高い商品の名前」や「最新の注文」などを取得できます。
サブクエリでLIMITを使用
-- 最も高価な商品と同じカテゴリの商品を取得
SELECT * FROM products
WHERE category = (
SELECT category FROM products
ORDER BY price DESC
LIMIT 1
)
ORDER BY price DESC;
| id |
name |
category |
price |
| 10 |
デスクトップPC |
電子機器 |
120,000 |
| 1 |
ノートPC |
電子機器 |
89,000 |
| 7 |
タブレット |
電子機器 |
55,000 |
| 4 |
モニター |
電子機器 |
45,000 |
| 12 |
プリンター |
電子機器 |
35,000 |
サブクエリで LIMIT 1 を使うと、スカラーサブクエリ(1行1列を返すサブクエリ)として利用でき、WHERE句の条件値として使えます。
UPDATE / DELETE でのLIMIT(MySQL限定)
MySQLでは、UPDATE文やDELETE文でもLIMIT句を使用できます。大量の行を一度に更新・削除するとロックが長時間保持されるため、バッチ処理で少しずつ処理する際に使います。
UPDATE / DELETE でのLIMIT(MySQL)
-- 古いデータを1000件ずつ削除(バッチ処理)
DELETE FROM access_logs
WHERE created_at < '2023-01-01'
LIMIT 1000;
-- 在庫を100件ずつ更新
UPDATE products
SET stock = 0
WHERE category = '廃止品'
LIMIT 100;
注意
UPDATE / DELETE での LIMIT は MySQL固有の機能 です。PostgreSQL、Oracle、SQL Server では使用できません。また、UPDATE / DELETE での LIMIT は ORDER BYと併用できません(MySQL 8.0時点)。どの行が処理されるかは不定のため、WHERE条件で確実に絞り込んでから使いましょう。
よくあるミスと注意点
LIMIT句を使う際に初心者がつまずきやすいポイントをまとめます。
ORDER BYなしのLIMITは順序不定
前述しましたが、非常に重要なので改めて強調します。ORDER BYを指定しない LIMIT は、どの行が返されるか保証されません。
ORDER BYなしのLIMIT(非推奨)
-- 悪い例: どの5件が返されるか不定
SELECT * FROM products LIMIT 5;
-- 良い例: ORDER BYで順序を明示
SELECT * FROM products
ORDER BY id
LIMIT 5;
データの追加・削除やインデックスの再構築後に結果が変わる可能性があるため、再現性が必要な場面では必ず ORDER BY を付けましょう。ただし、「とりあえずデータの中身を確認したい」といったテスト目的であれば ORDER BY なしでも問題ありません。
OFFSET指定のずれ(0始まり vs 1始まり)
OFFSETは 0始まり です。「1件目から」取得したい場合は OFFSET 0(または省略)を指定します。
OFFSETの0始まりに注意
-- 間違い: 2件目からになってしまう
SELECT * FROM products
ORDER BY id
LIMIT 5 OFFSET 1; -- 1件目がスキップされる
-- 正しい: 1件目から5件取得
SELECT * FROM products
ORDER BY id
LIMIT 5 OFFSET 0; -- またはOFFSET省略
| OFFSET値 |
スキップする行数 |
開始位置 |
| 0 |
0件 |
1件目から |
| 1 |
1件 |
2件目から |
| 5 |
5件 |
6件目から |
| 10 |
10件 |
11件目から |
LIMIT 0 の動作
LIMIT 0 を指定すると、結果は0件(空の結果セット)になります。エラーにはなりません。
LIMIT 0 の動作
-- 0件が返される(エラーにはならない)
SELECT * FROM products LIMIT 0;
-- 活用例: クエリの構文チェック(結果は不要だが構文を確認したい)
SELECT id, name, price, non_existent_column
FROM products
LIMIT 0; -- カラムが存在しなければエラーになる
これは一見無意味に見えますが、アプリケーション開発ではSQLの構文チェックや結果セットのカラム情報取得に使われることがあります。
GROUP BY + LIMIT の挙動
GROUP BYとLIMITを組み合わせる場合、LIMITはグループ化された後の結果に適用されます。「各グループから上位N件を取得する」という意味ではありません。
GROUP BY + LIMIT の挙動
-- カテゴリ別の集計から上位1グループだけ取得
SELECT category, COUNT(*) AS cnt
FROM products
GROUP BY category
ORDER BY cnt DESC
LIMIT 1;
-- 結果: 「周辺機器 7」(最も商品数が多いカテゴリ)
各グループから上位N件を取得したい場合
「各カテゴリから最も高い商品を1件ずつ取得」のような処理は、LIMITだけでは実現できません。ウィンドウ関数の ROW_NUMBER() OVER (PARTITION BY ...) を使います。
各カテゴリから上位1件ずつ取得
SELECT * FROM (
SELECT *,
ROW_NUMBER() OVER (
PARTITION BY category
ORDER BY price DESC
) AS rn
FROM products
) ranked
WHERE rn = 1;
| id |
name |
category |
price |
rn |
| 10 |
デスクトップPC |
電子機器 |
120,000 |
1 |
| 8 |
ヘッドセット |
周辺機器 |
12,000 |
1 |
MySQL省略記法の引数順序
MySQLの LIMIT offset, count 省略記法は引数の順序が直感に反するため、混同しやすいミスです。
MySQL省略記法の注意
-- LIMIT offset, count と LIMIT count OFFSET offset
LIMIT 10, 5 -- 10件スキップして5件取得
LIMIT 5 OFFSET 10 -- 同じ意味(こちらが読みやすい)
-- よくある間違い
LIMIT 5, 10 -- 意図: 5件取得 → 実際: 5件スキップして10件取得
推奨
可読性とRDBMS間の互換性を考慮し、LIMIT count OFFSET offset 形式を使うことを推奨します。省略記法 LIMIT offset, count はMySQLでしか使えず、引数の順序も紛らわしいです。
よくある質問(FAQ)
Q. LIMITとOFFSETの組み合わせでページネーションを実装するとき、大量データで遅くなります。解決策は?
A. OFFSET値が大きくなるほど全件スキャンが増えるため遅くなります。代替策はキーセットページネーション(カーソル方式):前ページの最後のIDを基準にWHERE id > last_id ORDER BY id LIMIT 10のようにします。インデックスが効きO(1)で取得できます。
Q. MySQLとPostgreSQLとSQL ServerでのLIMITの書き方の違いは?
A. MySQL/PostgreSQL: LIMIT 10 OFFSET 20。SQL Server: ORDER BY id OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY(ORDER BY必須)。Oracle(12c以降): FETCH FIRST 10 ROWS ONLYまたはOFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY。
Q. LIMIT/OFFSETを使わずに特定の行を取得する方法はありますか?
A. ROW_NUMBER()ウィンドウ関数を使う方法があります:SELECT * FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY id) AS rn FROM tbl) t WHERE rn BETWEEN 21 AND 30;。全RDBMSで動作し、複雑なソート条件でも対応できます。
まとめ
LIMIT句はSQLでデータの取得件数を制限するための重要な句です。この記事で学んだ内容を振り返りましょう。
| 目的 |
MySQL / PostgreSQL |
Oracle 12c+ |
SQL Server |
| 先頭N件 |
LIMIT N |
FETCH FIRST N ROWS ONLY |
SELECT TOP N |
| M件スキップしてN件 |
LIMIT N OFFSET M |
OFFSET M ROWS FETCH NEXT N ROWS ONLY |
OFFSET M ROWS FETCH NEXT N ROWS ONLY |
| 最新N件 |
ORDER BY 日付 DESC + 件数制限 |
| ランキングTOP N |
ORDER BY 集計値 DESC + 件数制限 |
| ページネーション |
OFFSET = (ページ番号 - 1) x 表示件数 |
この記事のポイント
- LIMIT句でSELECTの取得件数を制限できる(MySQL / PostgreSQL)
- ORDER BY + LIMITの組み合わせが実務の基本パターン
- OFFSETを使うとページネーション(ページ送り)が実装できる
- OracleとSQL ServerではFETCH FIRST / TOP / OFFSET-FETCHを使う
- OFFSETが大きいとパフォーマンスが低下する → カーソルベース方式で対策
- ORDER BYなしのLIMITは順序不定(再現性が必要なら必ずORDER BYを付ける)
- OFFSETは0始まり(1件目から取得 = OFFSET 0)
- 各グループからN件取得はROW_NUMBER() OVERを使う
LIMIT句はシンプルな構文ですが、ページネーションやパフォーマンスまで含めると奥が深い機能です。特にWebアプリケーション開発では、OFFSETの計算方法と大量データでのカーソルベースページネーションは押さえておきたい重要なテクニックです。RDBMSごとの構文の違いも把握して、環境に合った書き方を選択してください。