Welcome 微信登录

首页 / 数据库 / MySQL / [Oracle] ROWNUM和分页

rownum是Oracle的一个伪劣,它的顺序根据从表中获取记录的顺序递增,这里要注意的是:由于记录在表中是无序存放的,因此你无法通过简单的rownum和order by的组合获得类似TOP N的结果。Oracle 通过rownum实现分页 http://www.linuxidc.com/Linux/2011-05/35496.htm(Oracle)Rownum释疑 http://www.linuxidc.com/Linux/2013-05/84637.htmOracle数据库学习之Rownum http://www.linuxidc.com/Linux/2012-09/70061.htmOracle 中Rownum用法总结,Rownum 与 ROWID 区别 http://www.linuxidc.com/Linux/2012-07/66121.htmOracle利用Rownum和rowid分页 http://www.linuxidc.com/Linux/2012-04/58301.htmOracle数据库中Rownum分页 http://www.linuxidc.com/Linux/2012-02/53707.htm
 
我们的测试数据如下: select * from test;        ID NAME
---------- --------------------
       1 A
       3 C
       4 C
       8 C
        10 D
       2 B
       5 C
       7 C
       6 C
       9 D通过rownum<=5可以获得前5行数据:select * from test where rownum<=5;        ID NAME
---------- --------------------
       1 A
       3 C
       4 C
       8 C
        10 D如果你想获得像top n那样的结果,必须使用子查询:select * from (select * from test order by id) where rownum<=5;        ID NAME
---------- --------------------
       1 A
       2 B
       3 C
       4 C
       5 C如果你想获得第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;        ID NAME                       RN
---------- -------------------- ----------
       6 C                           6
       7 C                           7
       8 C                           8
       9 D                           9
        10 D                            10其实上面的写法是由陷阱的,不信你把order by id换成order by name试试看:select * from (select * from test order by name) where rownum<=5;        ID NAME
---------- --------------------
       1 A
       2 B
       3 C
       4 C
       8 C
 select T.* from (select t.*,rownum rn from (select * from test order by name) t where rownum<=10) T where T.rn>5;        ID NAME                       RN
---------- -------------------- ----------
       5 C                           6
       4 C                           7
       8 C                           8
        10 D                           9
       9 D                            10你会惊奇的发现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,保证不会出现并列的情况就可以了,如下所示: select * from (select * from test order by name,rowid) where rownum<=5;        ID NAME
---------- --------------------
       1 A
       2 B
       3 C
       4 C
       8 C
select T.* from (select t.*,rownum rn from (select * from test order by name,rowid) t where rownum<=10) T where T.rn>5;        ID NAME                       RN
---------- -------------------- ----------
       5 C                           6
       7 C                           7
       6 C                           8
        10 D                           9
       9 D                            10更多Oracle相关信息见Oracle 专题页面 http://www.linuxidc.com/topicnews.aspx?tid=12本文永久更新链接地址