🇯🇵 日本語 | 🇺🇸 English | 🇪🇸 Español | 🇵🇹 Português | 🇹🇭 ไทย | 🇨🇳 中文

【SQL】LIMIT句で表示件数を自在にコントロール!基本からページネーションまで徹底解説

「新着商品トップ5」「人気記事ランキングトップ10」「検索結果の1ページ目」… Webサイトやアプリでは、大量のデータの中から一部だけを切り取って表示する場面が頻繁にあります。そんな「件数制限」を実現するのが、SQLのLIMIT句です。

この記事では、Webクリエーターの皆さんに向けて、LIMIT句の基本的な使い方から、Web開発で必須のテクニック「ページネーション」の実装方法までを、豊富なサンプルコードと共に解説します。コピペで動かせるインタラクティブな実行環境も用意しました。ぜひ、実際に手を動かしながら、データをスマートに扱う強力な武器を手に入れてください!


まずは準備運動!今回もサンプルデータを使います

学習を始める前に、今回も架空のオンライン雑貨店「Web Creator's Mart」の商品テーブル(products)を使います。前回のORDER BYの記事を読んでくださった方は、見覚えがあるかもしれませんね。

以下のSQLは、テーブルの作成とデータの挿入を行うものです。ご自身の環境で試す場合や、後述する「動く実行環境」でもこのデータが使われますので、一度目を通しておいてください。

-- 商品テーブルの作成
CREATE TABLE products (
  id INT,
  name VARCHAR(255),
  category VARCHAR(255),
  price INT,
  release_date DATE
);

-- サンプルデータの挿入(7件)
INSERT INTO products (id, name, category, price, release_date) VALUES
(1, 'もふもふクッション', 'インテリア', 3200, '2023-04-15'),
(2, '集中できるイヤーマフ', 'ガジェット', 7800, '2023-11-01'),
(3, 'アイデア湧き出るノート', '文房具', 1200, '2022-08-20'),
(4, '光るキーボード', 'ガジェット', 15000, '2023-06-30'),
(5, '最高の座り心地チェア', 'インテリア', 32000, '2022-11-10'),
(6, 'なめらかボールペン', '文房具', 1200, '2023-09-01'),
(7, 'クリエイターマグカップ', '食器', 2500, '2023-04-15');

準備はできましたか?それでは、LIMIT句の世界へ飛び込んでみましょう!


LIMIT句の基本:取得する件数を指定する

LIMIT句の最もシンプルな使い方は、取得するレコード(行)の最大件数を指定することです。書き方は非常に簡単で、SELECT文の最後にLIMIT 件数と付け加えるだけです。

例えば、productsテーブルから、とりあえず3件だけデータを取得してみましょう。

SELECT * FROM products LIMIT 3;

これを実行すると、テーブルに格納されている順番で、先頭から3件のデータだけが返されます。とても直感的ですね。しかし、ここで一つ重要な注意点があります。このままでは「どの3件」が返ってくるか、実は保証されていません。データベースの内部的な都合で、実行するたびに結果の順序が変わる可能性すらあります。

LIMIT句の真価は、前回の記事で学んだORDER BYと組み合わせることで発揮されます。


最強タッグ!ORDER BY + LIMITで「TOP N件」を取得する

「価格が高い商品トップ3」「最近発売された商品トップ5」のような、いわゆる「TOP N件取得」は、Webサイトで頻出の要件です。これはORDER BYで並び替えた結果に対して、LIMITで件数を絞り込むことで実現できます。

まずは、「価格が高い商品トップ3」を取得してみましょう。ORDER BY price DESCで価格の高い順に並べ替え、その結果からLIMIT 3で上位3件を取得します。

-- 価格が高い商品トップ3を取得
SELECT * FROM products ORDER BY price DESC LIMIT 3;

どうでしょうか?「最高の座り心地チェア」「光るキーボード」「集中できるイヤーマフ」の3つが、この順で取得できたはずです。このように、ORDER BYで順序を確定させてからLIMITで切り取る、というのが黄金パターンです。必ずセットで使う、と覚えておきましょう。

同様に、「新着商品2件」も取得してみます。今度は発売日(release_date)を基準に並び替えます。

-- 発売日が新しい商品トップ2を取得
SELECT * FROM products ORDER BY release_date DESC LIMIT 2;

OFFSETで取得開始位置をずらす

LIMIT句のもう一人の相棒がOFFSETです。OFFSETは、その名の通り「ずらす、離れた場所」を意味し、「先頭から何件分のデータをスキップするか」を指定します。

例えば、「価格が高い順で、1位の商品は除外して、2位と3位の商品だけが欲しい」といった少し変わった要望に応えることができます。

-- 価格が高い順に並べ、最初の1件をスキップして、その後2件を取得
SELECT * FROM products ORDER BY price DESC LIMIT 2 OFFSET 1;

このSQLは、以下のように解釈されます。

  1. ORDER BY price DESCで、全商品を価格の高い順に並べる。
  2. OFFSET 1で、その結果の先頭1件(1位の商品)をスキップする。
  3. LIMIT 2で、スキップした位置から2件分のデータを取得する(結果的に2位と3位の商品が選ばれる)。

このLIMITOFFSETの組み合わせこそが、次のセクションで解説する「ページネーション」の心臓部となるのです。


応用編:LIMITとOFFSETで「ページネーション」を実装する

ページネーションとは、ブログの記事一覧やECサイトの商品一覧などで、大量のデータを複数ページに分割して表示する機能のことです。皆さんも「1, 2, 3, 4, 5, ... 次へ」のようなページャー(ページ切り替えナビ)を日常的に目にしているはずです。

このページネーションは、まさにLIMITOFFSETを使って実装されています。例えば、「1ページあたり3件ずつ」商品を表示する場合を考えてみましょう。

これをSQLで表現すると、以下のようになります。並び順がブレないように、ここではidでソートすることにします。

【1ページ目のSQL】

-- 1ページ目:0件スキップして3件取得
SELECT * FROM products ORDER BY id LIMIT 3 OFFSET 0;

【2ページ目のSQL】

-- 2ページ目:3件スキップして3件取得
SELECT * FROM products ORDER BY id LIMIT 3 OFFSET 3;

【3ページ目のSQL】

-- 3ページ目:6件スキップして3件取得
SELECT * FROM products ORDER BY id LIMIT 3 OFFSET 6;

お気づきでしょうか?LIMITの値(1ページあたりの表示件数)は常に3で固定です。そして、OFFSETの値(スキップする件数)は、0, 3, 6, ...と増えていきます。このOFFSETの値は、以下の簡単な計算式で求められます。

OFFSET = (現在のページ番号 - 1) * 1ページあたりの表示件数

この計算式をプログラムに組み込むことで、動的なページネーションが実現できるというわけです。言葉で説明するよりも、実際に動くものを見るのが一番です。次のセクションで、インタラクティブなページネーションを体験してみましょう!


【体験しよう!】ブラウザでSQLを直接実行してみる

お待たせしました!あなたのブラウザだけでSQLが実行できる、インタラクティブな実行環境を用意しました。これを使えば、この記事で学んだ様々なLIMIT句のパターンをご自身の手で試すことができます。

以下のコードをまるごとコピーしてindex.htmlなどのファイル名で保存し、ブラウザで開いてみてください。テキストエリアにこの記事のサンプルSQLを自由に貼り付けて「SQLを実行」ボタンを押してみましょう!

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>SQL Practice Environment</title>
  <style>
    body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; line-height: 1.6; color: #333; max-width: 800px; margin: 2rem auto; padding: 0 1rem; }
    h1, h2 { color: #444; border-bottom: 2px solid #eee; padding-bottom: 0.3em;}
    textarea { width: 100%; height: 150px; font-family: monospace; font-size: 16px; padding: 10px; border: 1px solid #ccc; border-radius: 4px; box-sizing: border-box; margin-bottom: 1rem; }
    button { background-color: #007bff; color: white; padding: 10px 20px; border: none; border-radius: 4px; cursor: pointer; font-size: 16px; }
    button:hover { background-color: #0056b3; }
    #result-container { margin-top: 1.5rem; min-height: 100px;}
    table { width: 100%; border-collapse: collapse; margin-top: 1rem; }
    th, td { border: 1px solid #ddd; padding: 10px; text-align: left; }
    th { background-color: #f8f8f8; }
    #error-message { color: red; font-weight: bold; margin-top: 1rem; }
  </style>
</head>
<body>

  <h1>SQLを動かして学ぶ!LIMIT句 練習場</h1>
  <p>下のテキストエリアにSQL文を入力して「実行」ボタンを押してください。記事で紹介した色々なSQLを試してみましょう!</p>

  <textarea id="sql-input">-- ここにSQLを貼り付けて実行!
-- 例:価格が高い商品トップ3
SELECT * FROM products ORDER BY price DESC LIMIT 3;</textarea>
  <button onclick="executeQuery()">SQLを実行</button>

  <h2>実行結果</h2>
  <div id="result-container"></div>
  <div id="error-message"></div>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/sql.js/1.10.3/sql-wasm.js"></script>
  <script>
    let db;

    async function initDb() {
      try {
        const SQL = await initSqlJs({
          locateFile: file => `https://cdnjs.cloudflare.com/ajax/libs/sql.js/1.10.3/${file}`
        });
        db = new SQL.Database();
        
        const setupSQL = `
          CREATE TABLE products (id INT, name VARCHAR(255), category VARCHAR(255), price INT, release_date DATE);
          INSERT INTO products (id, name, category, price, release_date) VALUES
          (1, 'もふもふクッション', 'インテリア', 3200, '2023-04-15'),
          (2, '集中できるイヤーマフ', 'ガジェット', 7800, '2023-11-01'),
          (3, 'アイデア湧き出るノート', '文房具', 1200, '2022-08-20'),
          (4, '光るキーボード', 'ガジェット', 15000, '2023-06-30'),
          (5, '最高の座り心地チェア', 'インテリア', 32000, '2022-11-10'),
          (6, 'なめらかボールペン', '文房具', 1200, '2023-09-01'),
          (7, 'クリエイターマグカップ', '食器', 2500, '2023-04-15');
        `;
        db.run(setupSQL);
        executeQuery(); // 初期SQLを実行
      } catch (e) {
        document.getElementById('error-message').textContent = 'データベースの初期化に失敗しました: ' + e.message;
      }
    }

    function executeQuery() {
      const sqlInput = document.getElementById('sql-input').value;
      const resultContainer = document.getElementById('result-container');
      const errorMessage = document.getElementById('error-message');
      
      resultContainer.innerHTML = '';
      errorMessage.innerHTML = '';

      try {
        const results = db.exec(sqlInput);
        if (results.length > 0) {
          resultContainer.appendChild(createTable(results[0]));
        } else {
          resultContainer.innerHTML = '<p>クエリは成功しましたが、結果セットは返されませんでした。(例: CREATE TABLE, INSERT)</p>';
        }
      } catch (e) {
        errorMessage.textContent = 'エラー: ' + e.message;
      }
    }

    function createTable(result) {
      const table = document.createElement('table');
      const thead = document.createElement('thead');
      const tbody = document.createElement('tbody');
      const headerRow = document.createElement('tr');
      result.columns.forEach(colName => {
        const th = document.createElement('th');
        th.textContent = colName;
        headerRow.appendChild(th);
      });
      thead.appendChild(headerRow);
      result.values.forEach(rowData => {
        const tr = document.createElement('tr');
        rowData.forEach(cellData => {
          const td = document.createElement('td');
          td.textContent = cellData;
          tr.appendChild(td);
        });
        tbody.appendChild(tr);
      });
      table.appendChild(thead);
      table.appendChild(tbody);
      return table;
    }

    initDb();
  </script>
</body>
</html>

補足:データベースによる方言について

今回解説したLIMIT ... OFFSET ...という構文は、MySQL, PostgreSQL, SQLiteなど多くのデータベースでサポートされている標準的な書き方です。しかし、一部のデータベースでは異なる構文(方言)を使用するため、参考までに紹介しておきます。

SQL Serverの場合

MicrosoftのSQL Serverでは、古くはTOP句が使われていましたが、最近のバージョンではOFFSET ... FETCH ...句が推奨されています。

-- SQL Serverでのページネーション(3件スキップして次の3件取得)
SELECT * FROM products
ORDER BY id
OFFSET 3 ROWS
FETCH NEXT 3 ROWS ONLY;

Oracleの場合

Oracle Databaseでも、SQL Serverと似たOFFSET ... FETCH ...構文が使われます。

-- Oracleでのページネーション(3件スキップして次の3件取得)
SELECT * FROM products
ORDER BY id
OFFSET 3 ROWS
FETCH NEXT 3 ROWS ONLY;

このように、データベースによって書き方が異なる場合があることは覚えておくと良いでしょう。しかし、基本的な考え方(「スキップする件数」と「取得する件数」を指定する)は全く同じです。


まとめ:LIMITを制する者は、データ表示を制する!

今回は、SQLのLIMIT句と、その相棒であるOFFSETについて、基本から応用までを掘り下げてきました。最後に、今日の重要なポイントを振り返りましょう。

必要なデータだけを、必要な分だけスマートに取得する。LIMIT句は、データベースのパフォーマンスを保ち、ユーザーにとって快適なUIを提供するための、非常に重要な機能です。ぜひ、デモ環境で色々と試してみて、その挙動を完全にマスターしてくださいね!