Oracle里那个rownum到底是啥,怎么用,有啥坑总结一下
- 问答
- 2025-12-26 01:47:38
- 1
Oracle里的rownum,说白了就是Oracle给查询结果每一行临时加上去的一个“伪列”,这个号码是从1开始编的,你可以把它想象成Excel表格最左边那个行号,Oracle在把你查出来的数据结果集摆到你面前的时候,顺手给每一行贴了个序号标签。
rownum是怎么工作的?
它的核心工作机制就三条,理解了这三条,就理解了它所有“古怪”行为的根源:
- 从1开始:rownum的赋值永远是从1开始的。
- 按顺序递增:Oracle在产生结果集的过程中,每选出一条符合条件的记录,才会给这条记录分配一个rownum,并且这个号码是递增的,1,2,3...这样下去。
- 有条件的分配:这是最关键也最让人困惑的一点。rownum是在数据被“选中”的过程中赋值的,而不是在最终的结果集形成之后才统一赋值的。
rownum的基本用法
最常见的用法就是用来限制返回的行数,实现分页或者取前N条记录。
-
取前10条记录:
SELECT * FROM employees WHERE rownum <= 10;
这个查询很好理解:Oracle一边从employees表里拿数据,一边给拿出来的数据编号(1,2,3...),一旦编到10号,条件
rownum <= 10就不满足了,它就停止搜索,把前10条返回给你。 -
和ORDER BY一起用(这里开始有坑了):
SELECT * FROM employees WHERE rownum <= 10 ORDER BY salary DESC;
你可能会以为这是取“工资最高的前10个人”,但错了,实际执行顺序是:Oracle先随便取出10条记录(比如按它在磁盘上存储的顺序),给这10条记录分配rownum(1到10),然后才对这小小的10条记录进行排序,你得到的只是“随机”10个员工按工资排序的结果,而不是全公司排序后的前10名。

rownum的那些“坑”总结
正是因为rownum那个“有条件分配”的工作机制,导致了一些反直觉的情况。
-
“坑”一:
rownum = 1可以,但rownum = 2、rownum > 1永远没结果 这是最经典的坑,为什么?- 当你写
rownum = 1:Oracle取出第一条数据,分配rownum=1,条件满足,这条记录被保留。 - 当你写
rownum = 2:Oracle取出第一条数据,分配rownum=1,条件rownum=2不满足(现在是1),所以这条记录被丢弃,然后它取第二条数据,注意,因为第一条被丢弃了,这第二条数据就变成了新的“第一条”,所以Oracle又给它分配了rownum=1!条件rownum=2依然不满足,又被丢弃……如此循环,没有任何一条记录能拿到rownum=2这个号码,所以结果永远是空的。 - 同理,
rownum > 1也一样,第一条数据拿到rownum=1,不满足>1,丢弃;第二条数据又变成新的第一条,拿到的还是1……永远没有记录能满足条件。
- 当你写
-
“坑”二:想要正确排序后取前N条,必须使用子查询 这就是为了解决上面提到的“排序失效”问题,正确的做法是分两步走:
SELECT * FROM ( SELECT * FROM employees ORDER BY salary DESC ) WHERE rownum <= 10;在这个语句里,最内层的子查询先执行,它会对全体员工按工资降序排序,生成一个“临时”的、排好序的结果集,外层的查询再从这个已经排好序的结果集里,从第一条开始取,取10条,这样你得到的才是真正工资最高的前10个人。

-
“坑”三:分页查询的写法更复杂 如果你想实现类似“每页10条,取第2页(即第11到20条)”的效果,不能直接写
rownum between 11 and 20(因为between包含等于,会掉进坑一的陷阱),标准的写法是:SELECT * FROM ( SELECT t.*, rownum AS rn -- 给内层查询的rownum起个别名保存下来 FROM ( SELECT * FROM employees ORDER BY salary DESC -- 先排序 ) t WHERE rownum <= 20 -- 控制上限:我要前20条 ) WHERE rn > 10; -- 再过滤:从第11条开始这里用了两层子查询,最内层负责排序;中间一层在排序的基础上,用
rownum <= 20取出前20条,并把rownum用别名rn固定下来(这是一个关键技巧,一旦有了别名,它就不再是“伪列”,而是一个普通的列值);最外层再基于这个固定的rn值来作大于判断(rn > 10),这样就绕开了rownum不能直接做大于比较的限制。 -
“坑”四:数据不是“绝对有序”的 即使你没有用ORDER BY,只是简单写
SELECT * FROM table WHERE rownum <= 10,这10条记录的顺序也不是绝对的,它通常取决于Oracle的数据读取路径(比如全表扫描的顺序),这个顺序可能和插入顺序有关,但不能被保证,只要查询没有明确的ORDER BY,结果的顺序就应该被视为是随机的。
总结一下
rownum是Oracle一个简单但机制独特的特性,它的核心是“在过程中按顺序分配号码”,用它来做“取前N条”非常方便,但一旦涉及到排序后的前N条或者分页,就必须借助子查询来“固化”行号或结果集顺序,牢记 rownum > N 或 rownum = N (N>1) 会返回空结果这个特性,就能避免大部分常见的错误。
(主要参考了Oracle官方文档中关于ROWNUM伪列的说明,以及大量Oracle开发者和DBA在技术社区如OTN、Oracle-Base等分享的经验总结。)
本文由瞿欣合于2025-12-26发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:https://haoid.cn/wenda/68505.html
