在 Oracle 数据库中,实现分页查询有几种常用方法,具体取决于 Oracle 的版本。下面我详细说明几种方法,并给出示例:

1️⃣ Oracle 12c 及以上版本 — 使用 OFFSET … FETCH

Oracle 12c 引入了 OFFSET … FETCH 语法,类似于 MySQLLIMIT。这是最简单、推荐的方式。

语法示例:

SELECT *
FROM employees
ORDER BY employee_id
OFFSET 10 ROWS      -- 跳过前 10 条记录
FETCH NEXT 5 ROWS ONLY;  -- 获取接下来的 5 条记录

说明:

  • OFFSET n ROWS:跳过前 n 条记录
  • FETCH NEXT m ROWS ONLY:获取 m 条记录
  • 必须配合 ORDER BY,否则分页结果可能不稳定

2️⃣ Oracle 11g 及以前版本 — 使用 ROWNUM 或子查询

在 11g 及以下版本,Oracle 没有 LIMIT,通常通过子查询和 ROWNUM 实现分页。

语法示例:

SELECT *
FROM (
    SELECT e.*, ROWNUM rnum
    FROM (
        SELECT *
        FROM employees
        ORDER BY employee_id
    ) e
    WHERE ROWNUM <= 15
)
WHERE rnum > 10;

说明:

  • 内层子查询 e 用于排序
  • 第二层查询使用 ROWNUM <= 15 限制最大行数
  • 外层查询 rnum > 10 实现分页起点

这里相当于获取 第 11~15 条记录

3️⃣ Oracle 11g 及以前版本 — 使用 ROW_NUMBER()

通过 ROW_NUMBER() 函数按指定排序生成行号,然后再分页。

语法示例:

SELECT *
FROM (
    SELECT e.*, ROW_NUMBER() OVER (ORDER BY employee_id) AS rn
    FROM employees e
) 
WHERE rn BETWEEN 11 AND 15;

说明:

  • ROW_NUMBER() OVER (ORDER BY ...) 给每行生成行号
  • WHERE rn BETWEEN start AND end 实现分页
  • 相比 ROWNUM 方法,更灵活,排序不会受 ROWNUM 限制

总结推荐

Oracle版本方法推荐理由
12c+OFFSET … FETCH简单明了,语法接近 MySQL
11g及以下ROW_NUMBER()灵活、可控、适合复杂分页
11g及以下ROWNUM + 子查询简单,但排序可能受限制

下面我写一个 通用的 Oracle 分页查询模板,直接套用就能分页,无论 11g 还是 12c 都适用。

这个模板使用 ROW_NUMBER(),在任何版本都可以用,也支持自定义排序和分页参数。

通用分页查询模板(Oracle 11g/12c 都可用)

-- 参数说明:
-- :page_number - 当前页码(从1开始)
-- :page_size   - 每页显示的记录数

SELECT *
FROM (
    SELECT t.*, 
           ROW_NUMBER() OVER (ORDER BY t.<排序列>) AS rn
    FROM <表名> t
    WHERE 1=1
      -- 可加其他查询条件,例如:
      -- AND t.status = 'ACTIVE'
) sub
WHERE rn BETWEEN (:page_number - 1) * :page_size + 1
              AND :page_number * :page_size;

示例:查询员工表第 2 页,每页 5 条记录

SELECT *
FROM (
    SELECT e.*, 
           ROW_NUMBER() OVER (ORDER BY e.employee_id) AS rn
    FROM employees e
) sub
WHERE rn BETWEEN (2 - 1) * 5 + 1
              AND 2 * 5;
  • 计算过程:
    • 起始行:(2-1)*5 + 1 = 6
    • 结束行:2*5 = 10
  • 实际返回 第 6~10 条记录

说明

  1. <排序列>必须指定,否则分页顺序不稳定。
  2. 可以在 WHERE 1=1 后添加更多筛选条件。
  3. 如果是 Oracle 12c+,也可以用更简洁的 OFFSET … FETCH
SELECT *
FROM employees
ORDER BY employee_id
OFFSET (:page_number-1)*:page_size ROWS
FETCH NEXT :page_size ROWS ONLY;