ROWNUM是Oracle执行查询时边生成边分配的伪列,不满足WHERE条件则不递增,故ROWNUM = N(N > 1)永远查不到;真正可控、排序后编号必须用ROW_NUMBER()窗口函数。
直接说结论:rownum不是“当前行号”,它是在结果集生成过程中动态分配的序号,且不可回溯;真正可控、可排序后编号的“当前行号”必须用row_number()分析函数。别在where里直接写rownum = 5,那永远查不到。
为什么ROWNUM = N(N > 1)查不到数据
ROWNUM是 Oracle 在执行查询时“边生成边编号”的伪列:第一行进来标为 1,第二行进来标为 2……但它只在行满足 WHERE 条件后才递增。所以 WHERE ROWNUM = 5 永远不成立——因为第 1 行进来时 ROWNUM 是 1,不等于 5,被过滤;第 2 行进来时 ROWNUM 还是 1(上一行没过,编号没递增),依然不等于 5……以此类推,整条语句返回空。
- 错误写法:
SELECT * FROM emp WHERE ROWNUM = 5→ 返回 0 行 - 正确思路:必须先让结果集完整生成并编号,再外层过滤 —— 用子查询套一层
- 等价但安全的写法:
SELECT * FROM (SELECT ROWNUM rn, e.* FROM emp e) WHERE rn = 5
ROW_NUMBER()才是真正的“按需编号”工具
ROW_NUMBER()是窗口函数,它在 ORDER BY 完成后才计算行号,因此能保证编号与业务逻辑一致。比如“工资最高的第 3 个人”,ROWNUM 做不了,ROW_NUMBER() 一行搞定。
- 基础用法:
SELECT name, salary, ROW_NUMBER() OVER (ORDER BY salary DESC) AS rn FROM emp - 分组内编号(如各部门薪资排名):
ROW_NUMBER() OVER (PARTITION BY deptno ORDER BY salary DESC) - 要取第 11–20 名:直接在外层加
WHERE rn BETWEEN 11 AND 20,不用嵌套两层 - 注意:
ROW_NUMBER()必须带OVER子句,否则报错ORA-30483: window functions are not allowed here
分页场景下ROWNUM和ROW_NUMBER()怎么选
老式分页(Oracle 11g 以前常用)靠 ROWNUM 嵌套,写法绕但兼容性好;新写法一律推荐 ROW_NUMBER(),逻辑直白、易维护、支持复杂排序和分组。
-
ROWNUM分页(第 2 页,每页 10 条):SELECT * FROM (SELECT ROWNUM rn, t.* FROM (SELECT * FROM emp ORDER BY hiredate) t WHERE ROWNUM 10 -
ROW_NUMBER()分页(同样需求):SELECT * FROM (SELECT e.*, ROW_NUMBER() OVER (ORDER BY hiredate) rn FROM emp e) WHERE rn BETWEEN 11 AND 20 - 关键区别:
ROWNUM版本中,ORDER BY必须放在最内层子查询,否则排序失效;ROW_NUMBER()的ORDER BY写在OVER里,位置明确,不怕错层 - 性能提示:两种方式在小数据量无明显差异;大数据量 + 复杂排序时,
ROW_NUMBER()可能多一次全排序,但语义清晰带来的可读性和可调优性更值钱
PL/SQL 块里想手动计数?别硬套ROWNUM
ROWNUM 是 SQL 层伪列,进 PL/SQL 游标循环后就失效了。想在过程里跟踪“这是第几行”,直接用变量累加就行,更可靠也更符合意图。
- 错误尝试:
FOR r IN (SELECT ROWNUM, name FROM emp) LOOP ... END LOOP;→ROWNUM在游标里只是普通列名,不自动更新 - 正解:
DECLARE i NUMBER := 0; BEGIN FOR r IN (SELECT name FROM emp) LOOP i := i + 1; DBMS_OUTPUT.PUT_LINE('第 ' || i || ' 行: ' || r.name); END LOOP; END; - 如果真需要把行号作为输出字段传给调用方,应在 SQL 查询里用
ROW_NUMBER()生成,而不是在 PL/SQL 里补
最容易被忽略的一点:很多人以为 ROWNUM 和 ROW_NUMBER() 只差一个括号,其实它们的执行时机、依赖顺序、适用场景完全不同。用错地方不光查不出数据,还可能在上线后因数据量变大突然暴露出排序错乱问题 —— 尤其当 ORDER BY 出现在外层或中间层时。


















