oracle关于rownum的【整理】

来源:互联网 发布:c语言 http post json 编辑:程序博客网 时间:2024/06/07 15:00

关于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个高得多。












阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 苏珊米勒 美国神婆 星运查询 天秤和双鱼 星弟 星弟几岁了 星弟是谁 星弟歌词大全 星沉海底当窗见 落到外星当宠物 带着农场当星嫂 带着农场当星嫂 晨光若樱 星形 星形线 星形接法和三角形接法 星形接法 星形接法三角形接法正规图解 星形连接 星形连接和三角形连接 电机星形接法和三角形接法 脊髓星形细胞瘤 星形细胞瘤三级生存期 星形胶质瘤 脑干星形细胞瘤 三相对称负载星形连接 三角形接法和星形接法的区别 星彩 星之彩 听话妈妈星彩乃 星彩乱舞 47933星彩 张星彩 星影 沙海免费观看全集星影 星恋 星恋byapple 动感之星恋恋影视 金有谦玟星恋情 星恒 星恒锂电池 星恒电源股份有限公司