oracle rownum错乱,Oracle中RowNum的隐藏陷阱

本文详细解析了 RowNum 在 SQL 查询中的工作原理及常见误区,包括如何正确地利用 RowNum 进行数据排序与筛选。

一.用RowNum来排序数据,或者生产FEntryId

有的时候我们习惯于这样使用RowNum

Create table B as select RowNum as Fseq,Fnumber From A order by Fnumber

我们希望在B表中得到一个按照Fnumber排序的数据,

这种代码使用方式在我们的代码里面很常见,比如我负责的固定资产模块.

然而结果往往事与愿维,B表中并未按照我们期望的那样实现按照Fnumber来排序,那问题究竟出在什么地方了?

要解决这个问题先要理解RowNum的含义

因为ROWNUM是对结果集加的一 个伪列,即先查到结果集之后再加上去的一个列 (强调:先要有结果集)。

任何事情都是这样,明白了原理,事情就会变得很简单,重点在于要先有结果集,

也就是说,正确的sql是这样

Create table B as select RowNum as Fseq, T.* from (select FNumber From A order by Fnumber) T

二.用RowNum来筛选数据

select * from A Where RowNum<10

我们可以通过这条语句来筛选前十条数据,很容易就得到了结果

但是

select * from A Where RowNum>10

我们却会发现

没有结果

Why?

别人删了?

查数据库,数据明明都在,超过10条

事情依然只有一个解释

那就是:

因为ROWNUM是对结果集加的一 个伪列,即先查到结果集之后再加上去的一个列 (强调:先要有结果集)。

查到的结果之后加上的伪列

简单的说rownum是对符合条件结果的序列号。它总是从1开始排起的。所以你选出的结果不可能没有1,而有其他大于1的值。所以您没办法期望得 到下面的结果集:

11 aaaaaaaa

12 bbbbbbb

13 ccccccc……

rownum >10 没有记录,因为第一条不满足去掉的话,第二条的ROWNUM又成了1,所以永远没有满足条件的记录

<think>好的,我现在要解决用户的问题:在Oracle数据库中使用ROWNUM实现分页查询,获取第10到20行的数据。用户之前提到了Hive中的实现,现在转向Oracle,需要明确两者的区别,并正确应用ROWNUM的方法。 首先,我需要回忆OracleROWNUM的工作原理。ROWNUM是一个伪列,它在查询结果返回前动态分配,从1开始递增。用户可能知道在直接使用ROWNUM=2时会失败,因为ROWNUM是在数据筛选后才分配的,所以只能用ROWNUM<=20这样的条件。 接下来,用户需要分页查询第10到20行的数据。正确的做法是使用子查询,外层筛选ROWNUM别名后的范围。参考用户提供的引用[3],示例中用了两层子查询,外层生成别名rn,然后筛选rn>1000和rn<2000。这应该适用于用户的需求,但需要调整参数到10-20行。 然后,我需要验证这个方法的正确性。比如,内层查询先筛选ROWNUM<=20,外层再筛选rn>=10。这样内层获取前20行,外层去掉前9行,得到10-20行。但要注意ROWNUM是在排序前分配的,所以需要确保正确的排序顺序。如果用户需要按特定顺序分页,必须在子查询中包含ORDER BY,否则数据顺序可能不符合预期。 另外,用户可能存在的误区是直接在WHERE子句中使用ROWNUM>=10,但这样不会有结果,因为ROWNUM是动态分配的,只有在行被选中后才会递增。所以必须通过子查询生成一个静态的rn列,才能进行范围筛选。 性能方面,当处理大数据量时,分页查询的效率可能较低,尤其是深层分页。用户可能需要优化,比如使用ROWID或物化视图,但用户当前的问题可能更关注基础实现,所以先给出标准方法,再补充优化建议。 还要考虑用户是否了解ROWNUM和ROW_NUMBER()的区别。ROW_NUMBER()是分析函数,可能在更复杂的情况下使用,但用户明确要求使用ROWNUM,所以应专注于ROWNUM的解决方案。 最后,确保回答结构清晰,步骤明确,并包含示例代码和注意事项,帮助用户正确应用方法,避免常见错误。同时,生成相关问题,引导用户深入理解分页机制和优化方法。</think>### Oracle中使用ROWNUM实现分页查询(第10到20行) 在Oracle中,`ROWNUM`是动态生成的伪列,直接通过`ROWNUM`进行范围筛选需要特定语法。以下是实现分页查询的标准方法和优化策略: --- #### **标准实现方法** 通过**两层子查询**实现分页逻辑: ```sql SELECT * FROM ( SELECT t.*, ROWNUM AS rn -- 为结果集添加行号 FROM ( SELECT * FROM your_table ORDER BY create_time DESC -- 必须明确排序字段(业务需求决定) ) t WHERE ROWNUM <= 20 -- 先取前20行 ) WHERE rn >= 10; -- 再筛选第10-20行 ``` **关键点解析**: 1. **内层排序**:必须在内层查询(最内层`t`子查询)中完成排序,否则分页结果顺序可能错乱。 2. **行号别名**:通过中间层子查询将`ROWNUM`固定为`rn`字段,才能在外层使用范围筛选[^3]。 --- #### **性能优化方案** 对于大数据表,可通过`ROWID`或`分析函数`优化: ##### 方法1:ROWID快速定位(适用于主键明确场景) ```sql SELECT * FROM your_table WHERE ROWID IN ( SELECT rid FROM ( SELECT ROWID AS rid, ROWNUM AS rn FROM your_table ORDER BY create_time DESC ) WHERE rn BETWEEN 10 AND 20 ); ``` ##### 方法2:ROW_NUMBER()窗口函数(Oracle 12c+) ```sql SELECT * FROM ( SELECT t.*, ROW_NUMBER() OVER (ORDER BY create_time DESC) AS rn FROM your_table t ) WHERE rn BETWEEN 10 AND 20; ``` --- #### **常见问题与解决方案** 1. **为什么直接`WHERE ROWNUM >= 10`无效?** `ROWNUM`在数据逐行返回时动态生成,当执行`ROWNUM >= 10`时,第一行`ROWNUM=1`不满足条件会被丢弃,导致后续行永远无法满足条件[^1]。 2. **如何保证分页结果稳定?** - 必须指定唯一排序字段(如主键`ORDER BY id, create_time`),避免数据重复导致分页结果跳跃[^3]。 - 使用事务隔离级别`READ COMMITTED`防止并发修改影响结果。 3. **深层分页性能差怎么办?** - 通过`WHERE`条件缩小数据范围(如`WHERE create_time > '2023-01-01'`)。 - 使用物化视图缓存排序结果。 --- #### **对比ROWNUM与ROW_NUMBER()** | 特性 | ROWNUM | ROW_NUMBER() | |-------------------|------------------------------|----------------------------| | **生成逻辑** | 动态生成,过滤前分配 | 静态分配,基于完整排序结果 | | **性能** | 快速(跳过前N行) | 需要全排序,大数据量较慢 | | **语法复杂度** | 需嵌套子查询 | 单层查询即可实现 | --- ### **扩展应用:动态分页参数** 通过绑定变量实现动态分页: ```sql SELECT * FROM ( SELECT t.*, ROWNUM AS rn FROM ( SELECT * FROM employees ORDER BY hire_date ) t WHERE ROWNUM <= :end_row -- 绑定变量(如end_row=20) ) WHERE rn >= :start_row; -- 绑定变量(如start_row=10) ``` --- ### **注意事项** 1. **排序字段选择**:若使用非唯一字段排序,需添加第二排序字段(如主键)保证分页稳定性。 2. **索引优化**:为排序字段创建索引(如`CREATE INDEX idx_hire_date ON employees(hire_date)`)可显著提升性能[^2]。 --- ### 相关问题 1. Oracle中`ROWNUM`和`ROWID`有什么区别? 2. 如何优化Oracle深层分页(如第10000页)的查询性能? 3. Oracle 12c的`FETCH FIRST/NEXT`语法如何实现分页?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值