Oracle数据库本身没有像MySQL那样直接的LIMIT分页语法,实际开发中通常使用ROWNUM伪列来实现分页查询功能,ROWNUM是Oracle为查询结果集中的每一行分配的一个序号,从1开始递增。

Oracle分页查询的核心原理
ROWNUM的特性是,它是在查询结果返回之后才进行编号的,而且只能使用小于号或者小于等于号进行筛选,不能直接使用大于号或者大于等于号。如果直接使用大于号筛选,会返回空结果,因为ROWNUM从1开始,第一条数据不满足大于N的条件就会被过滤,后续数据的ROWNUM也不会再生成。
两种常用的分页查询写法
写法一:两层嵌套查询
这是最经典的分页写法,先在内层查询中给所有数据加上ROWNUM,然后在外层查询中筛选ROWNUM的范围,实现分页效果。假设我们要查询用户表user_info,每页显示10条数据,查询第2页的数据,示例代码如下:
-- 查询user_info表第2页数据,每页10条
SELECT *
FROM (
SELECT t.*, ROWNUM rn
FROM (
-- 内层是最原始的业务查询SQL,可以加排序等条件
SELECT * FROM user_info ORDER BY create_time DESC
) t
WHERE ROWNUM <= 20 -- 结束行号,页大小*页码,这里10*2=20
)
WHERE rn >= 11 -- 起始行号,(页大小*(页码-1))+1,这里10*(2-1)+1=11
写法二:使用ROW_NUMBER()分析函数
除了使用ROWNUM,还可以使用Oracle的分析函数ROW_NUMBER()来实现分页,这种方式可以在查询时直接生成行号,不需要额外嵌套一层给ROWNUM取别名。同样查询第2页10条数据的示例代码如下:
SELECT *
FROM (
SELECT t.*, ROW_NUMBER() OVER (ORDER BY create_time DESC) AS rn
FROM user_info t
)
WHERE rn BETWEEN 11 AND 20 -- 直接筛选行号范围,11到20对应第2页
常见错误写法及原因
很多开发者刚接触Oracle分页时会写出下面的错误代码:
-- 错误写法示例 SELECT * FROM user_info WHERE ROWNUM >= 11 AND ROWNUM <= 20 ORDER BY create_time DESC
这段SQL会返回空结果,原因就是前面提到的ROWNUM特性:ROWNUM是从1开始分配的,第一条数据的ROWNUM是1,不满足>=11的条件就会被过滤,后续数据不会再生成ROWNUM,所以最终查询不到任何数据。另外如果先加WHERE ROWNUM条件再排序,排序后的行号会混乱,不符合预期的分页顺序,所以排序操作一定要放在最内层的查询中。
分页参数说明
分页查询中常用的参数对应关系如下:
| 参数名称 | 含义 | 计算方式 |
|---|---|---|
| pageNum | 当前页码 | 从1开始传入 |
| pageSize | 每页条数 | 根据业务需求设定,比如10、20 |
| startRow | 起始行号 | pageSize * (pageNum - 1) + 1 |
| endRow | 结束行号 | pageSize * pageNum |
实际开发注意事项
- 最内层的查询一定要先完成排序、过滤等业务逻辑,再进行分页操作,避免分页后的数据顺序不符合预期。
- 如果查询的数据量非常大,建议在排序列上建立索引,提升分页查询的效率,尤其是深分页场景。
- 两种写法都可以实现分页功能,两层嵌套ROWNUM写法是Oracle早期常用的方式,兼容性更好;ROW_NUMBER()写法逻辑更直观,适合熟悉分析函数的开发者使用。