ROWNUM是Oracle独有的伪列,从1开始连续编号,仅支持ROWNUM = 1、ROWNUM <= N、ROWNUM BETWEEN 1 AND N等“从1起始”的条件;ROWNUM > 1、= 2、> 10等均返回空,因其在行筛选时动态赋值且不递增。

WHERE ROWNUM
直接用 WHERE ROWNUM 可以稳定取前 N 行,这是 Oracle 唯一不会出错的 Top-N 写法。它不依赖排序、不关心表结构、也不要求索引,只要 SQL 能执行,结果就确定。
常见错误是加了 ORDER BY 还写成 SELECT * FROM t WHERE ROWNUM ——这实际取的是“物理读取顺序的前 10 行”,再对这 10 行排序,根本不是最新 10 条数据。
- 想按时间取最新 10 条:必须先在子查询里
ORDER BY,再外层套ROWNUM -
ROWNUM = N(N > 1)永远无结果;ROWNUM > N同样永远无结果 - 如果只想要数量限制、不关心顺序(比如快速抽样),
WHERE ROWNUM 就够用,性能也最好
ROWNUM 分页必须用两层嵌套
要取第 11–20 行,不能写 WHERE ROWNUM BETWEEN 11 AND 20,也不能写 WHERE ROWNUM >= 11 AND ROWNUM ——这两者都查不到任何行。
正确结构是:最内层排序 → 中间层分配 ROWNUM 并截断到上限 → 外层用别名过滤下限。
SELECT * FROM (
SELECT a.*, ROWNUM rn FROM (
SELECT * FROM employees ORDER BY salary DESC
) a WHERE ROWNUM <= 20
) WHERE rn > 10- 内层
WHERE ROWNUM 是为了触发 Oracle 的 Top-N 优化,避免全表排序 - 中间层必须给
ROWNUM起别名(如rn),否则外层无法引用 - 外层条件只能用别名(
rn > 10),不能用ROWNUM,否则又掉进伪列陷阱
ROWNUM 和 ORDER BY 的执行顺序是硬伤
Oracle 先分配 ROWNUM,再执行 ORDER BY。这意味着:只要 ROWNUM 出现在 WHERE 子句里,排序就一定发生在行号分配之后——除非你把它塞进子查询里。
这个顺序不是 bug,是设计如此。所以以下写法全部无效:
SELECT * FROM t ORDER BY x DESC WHERE ROWNUM (语法错误,<code>WHERE不能在ORDER BY后)SELECT * FROM t WHERE ROWNUM (逻辑错误,排序对象是前 10 行,非全局前 10)-
SELECT ROWNUM, t.* FROM t ORDER BY x DESC(ROWNUM仍是原始顺序,和ORDER BY无关)
真正起作用的只有带子查询的三段式结构,没有捷径。
替代方案:ROW_NUMBER() 更直观但有开销
如果 Oracle 版本 ≥ 8.1.6,可以用窗口函数 ROW_NUMBER() OVER (ORDER BY ...) 替代 ROWNUM 实现分页。它在排序后编号,语义更接近直觉。
SELECT * FROM ( SELECT e.*, ROW_NUMBER() OVER (ORDER BY salary DESC) rn FROM employees e ) WHERE rn BETWEEN 11 AND 20
-
ROW_NUMBER()会强制对全结果集排序,大数据量时比ROWNUM嵌套慢 - 但它支持
PARTITION BY,能做组内排名,ROWNUM完全做不到 - 跨数据库迁移时,
ROW_NUMBER()比ROWNUM更通用(MySQL 8.0+/PostgreSQL/SQL Server 都支持)
复杂分页或需要组内序号时,ROW_NUMBER() 是更可靠的选择;单纯取前 N 行,ROWNUM 更轻量。


















