转自:https://blog.csdn.net/qiuzhi__ke/article/details/78892822

关于rownum是怎么产生的(网上有不少的文章,下面是摘录):

rownum是在where条件过滤之后,在任何排序(order by)或聚集(aggregation)之前赋给行的。同时,只有当rownum被分配给行后才会递增。rownum的初始值为1。rownum在查询中产生后就不再变化:

select * from emp where ROWNUM <= 5 order by sal desc;

该语句的目的是想返回top 5薪水最高的员工信息,但根据rownum的产生原理,rownum在order by之前就已经产生,所以该语句并不能起到top 5的作用,正确的语法如下:

select * from (select * from emp order by sal desc) where ROWNUM <= 5;

rownum是Oracle的一个伪列,它的顺序根据从表中获取记录的顺序递增,这里要注意的是:由于记录在表中是无序存放的,因此你无法通过简单的rownum和order by的组合获得类似TOP N的结果。

因为ROWNUM是对结果集加的一个伪列,即先查到结果集之后再加上去的一个列 (强调:先要有结果集)。简单的说rownum 是对符合条件结果的序列号。它总是从1开始排起的。所以你选出的结果不可能没有1,而有其他大于1的值。

如果你想获得像top n那样的结果,必须使用子查询:

select * from (select * from test order by id) where rownum<=5;

如果你想获得第5行到第10行之间的数据,则必须再加一层子查询:

select T.* from (select t.*,rownum rn from (select * from test order by id) t where rownum<=10) T where T.rn>5;

其实上面的写法是由陷阱的,不信你把order by id换成order by name

你会惊奇的发现id=4这条数据出现在了两个地方,这不合逻辑!但事实就是这样的,为什么呢?因为name不唯一,两次排序取出的结果有可能会不一样,我还是举个例子吧:

select id,name,rank() over(order by name) from test;

ID NAME                RANK()OVER(ORDERBYNAME)

---------- -------------------- -----------------------

        1 A                                          1

        2 B                                          2

        6 C                                          3

        3 C                                          3

        4 C                                          3

        8 C                                          3

        5 C                                          3

        7 C                                          3

        9 D                                          9

        10 D                                          9

从上面的结果我们不难发现,根据name排序,有多条数据并列排在第3位,这样,当取前5名时,到底在并列第3中取哪几位就不是确定的事,因此就出现了之前出现的诡异的问题。那么,怎样才能彻底解决这个问题呢?其实只要在order by name后面加上rowid,保证不会出现并列的情况就可以了

排序列不唯一所带来的问题

如果用来排序的列不唯一,也就是存在值相等的行,可能会造成第一次在前10条返回记录中,某行数据出现了,而第二次在11到第20条记录中,某行数据又出现了。一条数据重复出现两次,就必然意味着有数据在两次查询中都不会出现。

 

 其实造成这个问题的原因很简单,是由于排序列不唯一造成的。Oracle这里使用的排序算法不具有稳定性,也就是说,对于键值相等的数据,这种算法完成排序后,不保证这些键值相等的数据保持排序前的顺序。

 

 解决这个问题其实也很简单。有两种方法可以考虑。

1)在使用不唯一的字段排序时,后面跟一个唯一的字段。

一般在排序字段后面跟一个主键就可以了,如果表不存在主键,跟ROWID也可以。这种方法最简单,且对性能的影响最小。

2)另一种方法就是使用前面给出过多次的BETWEEN AND的方法。

这种方式由于采用表数据的全排序,每次只取全排序中的某一部分数据,因此不会出现上面提到的重复数据问题。

但是正是由于使用了全排序,而且ROWNUM信息无法推到查询内部,导致这种写法的执行效率很低

分页查询格式1

在查询的最外层控制分页的最小值和最大值。查询语句如下:  

SELECT * FROM 

(

SELECT A.*, ROWNUM RN 

FROM (SELECT * FROM TABLE_NAME) A 

)

WHERE RN BETWEEN 21 AND 40

分页查询格式2 

SELECT * FROM 

(

SELECT A.*, ROWNUM RN 

FROM (SELECT * FROM TABLE_NAME) A 

WHERE ROWNUM <= 40

)

WHERE RN >= 21

分页查询格式3

考虑到多表联合的情况,如果不介意在系统中使用HINT的话,可以将分页的查询语句改写为: 

SELECT /*+ FIRST_ROWS */ * FROM 

(

SELECT A.*, ROWNUM RN 

FROM (SELECT * FROM TABLE_NAME) A 

WHERE ROWNUM <= 40

)

WHERE RN >= 21

效率问题

 对比这两种写法,绝大多数的情况下,第2个查询的效率比第1个高得多。

分页查询格式4

利用row_number()函数

SELECT  *

FROM    (

        SELECT  t.*, ROW_NUMBER() OVER (ORDER BY paginator, id) AS rn

        FROM    mytable t

        )

WHERE   rn BETWEEN 900001 AND 900010

分页查询格式5

SELECT  *

FROM    (

        SELECT  t.*, ROWNUM AS rn

        FROM    (

                SELECT  * FROM mytable ORDER BY paginator, id

                ) t

        )

WHERE   rn >= 900001

        AND rownum <= 10

oracle中row_number()

1、row_number() over (order by col_1[,col_2 ...])

按照col_1[,col_2 ...]排序,返回排序后的结果集,并且为每一行返回一个不相同的值。

2、row_number() over (partition by col_n[,col_m ...] order by col_1[,col_2 ...])

先按照col_n[,col_m ...进行分组,再在每个分组中按照col_1[,col_2 ...]进行排序(升序),最后返回排好序后的结果集

row_number()over(partition by col1 order by col2)表示根据col1分组,在分组内部根据col2排序,而此函数计算的值就表示每组内部排序后的顺序编号(组内连续的唯一的)。 与rownum的区别在于:使用rownum进行排序的时候是先对结果集加入伪劣rownum然后再进行排序,而row_number()在包含排序从句后是先排序再计算行号码。

其他参考:

oracle中rownum和row_number()

http://www.jb51.net/article/65960.htm

oracle中row_number和rownum的区别和联系(翻译)

https://www.cnblogs.com/jcz1206/p/4378076.html

oracle关于rownum的使用【oracle】的更多相关文章

  1. ORACLE 中ROWNUM用法总结(转)

    ORACLE 中ROWNUM用法总结! 对于 Oracle 的 rownum 问题,很多资料都说不支持>,>=,=,between...and,只能用以上符号(<.<=.!=) ...

  2. 【Oracle】oracle中rownum的说明及使用技巧

    oracle中常用到ROWNUM,所以做一些本人对rownum的一些认识和使用技巧的记录,以便备查. 一.rownum的说明 rownum是oracle特有的一个关键字. (1)对于基表,在inser ...

  3. oracle之rownum(伪列)

    整理和学习了一下网上高手关于rownum的帖子: 参考资料:  http://tech.ddvip.com/2008-10/122490439383296.html 和 http://tenn.jav ...

  4. Oracle中rownum和rowid的理解(转)

    本文转自地址http://www.linuxidc.com/Linux/2012-04/58300.htm rownum,rowid都叫伪列. 但是,rownum是逻辑上的编号,且其值总是从1开始,每 ...

  5. oracle 中 rownum 和 row_number()

    简单的介绍下oracle 中rownum 和 row_number() 使用,实例演示. 参照:http://www.cnblogs.com/zjrstar/archive/2006/08/31/49 ...

  6. oracle中rownum和rowid的区别

    rownum和rowid的区别总括: rownum和rowid都是伪列,但是两者的根本是不同的. rownum是根据sql查询出的结果给每行分配一个逻辑编号,所以你的sql不同也就会导致最终rownu ...

  7. ORACLE 中ROWNUM用法总结!

    ORACLE 中ROWNUM用法总结! 对于 Oracle 的 rownum 问题,很多资料都说不支持>,>=,=,between...and,只能用以上符号(<.<=.!=) ...

  8. [转]ORACLE 中ROWNUM用法总结!

    原文地址:http://www.itpub.net/thread-824147-1-1.html 对于 Oracle 的 rownum 问题,很多资料都说不支持>,>=,=,between ...

  9. oracle 分页(rownum的理解) 以及 树节点的查询

    1:什么是rownum, rownum的生成, rownum相关的符号操作 Rownum是oracle生成结果集时得到的一个伪列, 按照读出行的顺序, 第一条rownum=1, 第二条=2. 对于 O ...

  10. Oracle的rownum原理和使用

    整理和学习了一下网上高手关于rownum的帖子: 参考资料:  http://tech.ddvip.com/2008-10/122490439383296.html 和 http://tenn.jav ...

随机推荐

  1. Spring Boot JPA的查询语句

    文章目录 准备工作 Containing, Contains, IsContaining 和 Like StartsWith EndsWith 大小写不敏感 Not @Query Spring Boo ...

  2. Scala教程之:Either

    在之前的文章中我们提到了Option,scala中Option表示存在0或者1个元素,如果在处理异常的时候Option就会有很大的限制,因为Option如果返回None,那么我并不知道具体的异常到底是 ...

  3. Element UI表格组件技巧:如何简洁实现跨页勾选、跨页统计功能

    业务场景 在使用Element UI的Table组件时,常常面对这样的业务需求: 表格数据的每一项都要提供勾选框,当切换分页时,能够记忆所有页面勾选的数据,以实现批量提交不同页面勾选数据的功能.并且, ...

  4. 酷狗音乐快速转换MP3格式的方法

    喜欢听音乐的朋友们,散步跑步的时候都是随身听,音乐可以给人带来力量,让人心情愉悦,有时候甚至还可以让我们忘记烦恼和忧愁,是一种不错的解压方式,所以热爱运动的宝宝们是离不来音乐的陪伴的,这样说来随身听的 ...

  5. 数学--数论--HDU1825(积性函数性质+和函数公式+快速模幂+非互质求逆元)

    As we all know, the next Olympic Games will be held in Beijing in 2008. So the year 2008 seems a lit ...

  6. Codeforce 1098-A

    A. Sum in the tree   Mitya has a rooted tree with nn vertices indexed from 11 to nn, where the root ...

  7. muduo网络库源码学习————日志滚动

    muduo库里面的实现日志滚动有两种条件,一种是日志文件大小达到预设值,另一种是时间到达超过当天.滚动日志类的文件是LogFile.cc ,LogFile.h 代码如下: LogFile.cc #in ...

  8. 简单模拟实现Rxjs Observable

    1.先定义类型 export type Observer = { next: (any) => void, complete?: (any) => void, } export inter ...

  9. 常用中文分词工具分词&词性标注简单应用(jieba、pyhanlp、pkuseg、foolnltk、thulac、snownlp、nlpir)

    1.jieba分词&词性标注 import jieba import jieba.posseg as posseg txt1 =''' 文本一: 人民网华盛顿3月28日电(记者郑琪)据美国约翰 ...

  10. 设计模式GOF23之单例模式

    单例模式的五种方式 主要:懒汉式,饿汉式 其他:双重检测锁(Double Checking模式),静态内部类,枚举模式 选取时机 延时加载,占用内部资源大:静态内部类好于懒汉 不延时加载,占用内部资源 ...