rownum > 10 永远查不到数据,因其在结果生成时动态赋值:首行标为1后因不满足>10被丢弃,次行重标为1,循环往复;故需用子查询先限制 rownum ≤ 10 再筛选。

WHERE ROWNUM
直接写 WHERE ROWNUM > 10 永远查不到数据,因为 ROWNUM 是在结果集生成过程中动态分配的:第一行进来标为 1,不满足 >10 就丢弃;第二行又变成 1,继续丢弃……根本不会出现 11。所以必须用
常见错误包括:
SELECT * FROM emp WHERE ROWNUM > 5 AND ROWNUM —— 语法看似合理,实际无结果- 把
ORDER BY放在外层或中间层但没套进最内层子查询 —— 排序失效,分页错乱 - 漏写中间层的
WHERE ROWNUM —— Oracle 会全表扫描+排序,性能雪崩
三层嵌套结构是可靠分页的最小必要形式
不是为了炫技,而是让「排序」「编号」「截断」三件事各司其职:
- 最内层:只写
SELECT ... FROM table WHERE ... ORDER BY xxx,确保逻辑顺序正确 - 中间层:对已排序结果加
ROWNUM AS rn,并立即用WHERE ROWNUM 截断物理读取(这是性能关键) - 最外层:用
WHERE rn > (:page_number - 1) * :page_size过滤起始位置,此时rn已是普通数值列,可安全比较
例如查第 3 页、每页 15 条:
SELECT * FROM (
SELECT * FROM (
SELECT * FROM employees ORDER BY employee_id
) WHERE ROWNUM 30;
OFFSET FETCH 更简洁,但有硬性前提
如果你用的是 Oracle 12c 及以上版本,OFFSET FETCH 确实更直观,但它有两个不可绕过的条件:
- 数据库版本必须 ≥ 12c —— 11g 或更早会报
ORA-00933: SQL command not properly ended -
ORDER BY必须出现在OFFSET前且不能省略 —— 没有排序依据的分页没有业务意义,Oracle 会直接拒绝执行 -
OFFSET参数只能是整数,传浮点数或负数会报错,不能用ROUND()或CEIL()动态计算后直接拼入
正确示例:
SELECT * FROM employees ORDER BY employee_id OFFSET 30 ROWS FETCH NEXT 15 ROWS ONLY;
rownum 分页容易被忽略的排序陷阱
很多人以为加了 ORDER BY 就万事大吉,其实不然。如果 ORDER BY 字段没有索引,或者排序字段存在大量重复值,ROWNUM 分页会出现“同一页数据跨页重复”或“跳号”现象 —— 因为 Oracle 在未强制稳定排序时,相同排序键的行物理顺序可能每次都不一样。
解决方法只有两个:
- 确保
ORDER BY后追加主键或唯一字段,例如ORDER BY status, id - 改用
ROW_NUMBER() OVER (ORDER BY ...)替代ROWNUM,它支持窗口内稳定编号,但注意它不带物理截断能力,仍需配合子查询限制范围
真正难的不是写出能跑的 SQL,而是让分页在高并发、大数据量、多重复值场景下不翻车 —— 这一点,光靠语法正确远远不够。











