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

【SQL】掌握 LIMIT 子句!从基础到分页的全面解析

“最新商品前5名”、“热门文章排行榜前10名”、“搜索结果的第1页”……在网站或应用中,经常需要从大量数据中筛选出一部分进行显示。而实现这种“数量限制”的强大 SQL 工具就是 LIMIT 子句

本文面向网页创作者,从 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 获取「前 N 条数据」

像「价格最高的前 3 个商品」「最新发布的前 5 个商品」这类需求,在网站开发中非常常见。这类「TOP N 获取」功能可以通过先使用 ORDER BY 进行排序,再用 LIMIT 限制条数来实现。

首先尝试获取「价格最高的前 3 个商品」,通过 ORDER BY price DESC 降序排序后,再使用 LIMIT 3 限制结果数。

-- 获取价格最高的前 3 个商品
SELECT * FROM products ORDER BY price DESC LIMIT 3;

你应该得到了「最舒适的椅子」「发光键盘」「专注耳罩」这三项数据,按顺序返回。这种先使用 ORDER BY 确定顺序,再用 LIMIT 截取 的组合是黄金法则,请务必记住。

接下来也可以获取「最新发布的 2 件商品」,这次以 release_date 为基准排序:

-- 获取最新发布的前 2 个商品
SELECT * FROM products ORDER BY release_date DESC LIMIT 2;

使用 OFFSET 来偏移获取起始位置

LIMIT 的另一位好搭档是 OFFSET,表示偏移位置。它用于跳过前面指定条数的记录,非常实用。

比如说,如果你想要「价格第 2 和第 3 高的商品,不包括第 1 名」,这时就可以使用 OFFSET 来跳过前一条数据。

-- 按价格降序排列,跳过第一条,获取接下来的两条
SELECT * FROM products ORDER BY price DESC LIMIT 2 OFFSET 1;

这条 SQL 的含义如下:

  1. ORDER BY price DESC:按价格从高到低排序所有商品
  2. OFFSET 1:跳过排序结果中的第一条
  3. LIMIT 2:从跳过的位置开始,获取 2 条数据(即第 2、3 高价格)

这种 LIMIT + OFFSET 的组合方式,正是下一节要讲的「分页显示」功能的核心实现方式。


进阶应用:使用 LIMIT 和 OFFSET 实现分页(Pagination)

分页(Pagination) 是指将大量数据分成多页显示的功能,常用于博客文章列表、电商商品页等。你肯定见过「1, 2, 3, … 下一页」这样的分页导航吧?

这种分页功能,其实正是通过 LIMITOFFSET 实现的。假设每页显示 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 的值(每页显示条数)固定为 3,而 OFFSET 的值是 0, 3, 6,...。你可以用如下公式动态计算:

OFFSET = (当前页码 - 1) × 每页显示条数

将此公式写入程序,就能实现自动分页功能。与其听解释,不如亲眼看看实际效果吧!接下来的章节会展示一个可互动的分页示例。


【动手试试看!】在浏览器中直接执行 SQL

感谢您的等待!我们为您准备了一个交互式 SQL 运行环境,只需使用您的浏览器即可运行 SQL。您可以亲手试验本文中讲解的各种 LIMIT 子句用法。

将以下代码完整复制,保存为 index.html,然后用浏览器打开。将文章中的 SQL 示例粘贴到文本框中,点击“执行 SQL”按钮即可查看结果!

<!DOCTYPE html>
<html lang="zh">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>SQL 练习环境</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”按钮。来试试文章中讲解的各种 SQL 示例吧!</p>

  <textarea id="sql-input">-- 在此粘贴 SQL 并执行
-- 示例:价格最高的前三个商品
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();
      } 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>SQL 执行成功,但无返回结果集(如: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 資料庫也使用類似 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 的使用方法!