Oracle的分页是通过rownum实现的。
rownum是一个伪列,是oracle系统自动为查询返回结果的每行分配的编号,第一行为1,第二行为2,以此类推。。。。
一个oracle分页,至少要包含三层(除非不用order by,暂时可以用2层实现),模板为
select temp2.* from(
select rownum num,temp1.* from(
SQL查询
) temp1 where rownum<=n1
)temp2 where temp2.num>n2
例如:值返回查询结果第11条到20条着10条的信息的SQL如下:
select temp2.*
from(
select rownum num,temp1.*
from(
select tt.title_id,tt.name
from t_title tt
where tt.name like '%美%'
order by tt.sort_seqs asc,tt.title_Id desc) temp1
where rownum<=20
)temp2
where temp2.num>10
分析:
1.首先是一个正常的查询语句(包含order by)
select tt.title_id,tt.name
from t_title tt
where tt.name like '%美%'
order by tt.sort_seqs asc,tt.title_Id desc
这个和正常的SQL语句没有任何的区别
2.添加rownum字段,显示列数
select rownum num,temp1.*
from(
select tt.title_id,tt.name
from t_title tt
where tt.name like '%美%'
order by tt.sort_seqs asc,tt.title_Id desc) temp1
where rownum<=20
我们添加了rownum 显示字段,这时候就会会每行添加一个行数的编号;并且只返回20条之前的数据(包含20条)
3.截取第10条到20条的数据,SQL就是上面最完整的那个啦。
使用精解:
1.rownum的使用:
如下两条语句:
select rownum,id,name from student where rownum>2;
select rownum,id,name from student where rownum<=10;
第一条语句的执行结果为空,第二条语句的执行结果为前10条记录;
为什么会这样呢,我们知道rownum是伪列,是oracle为查询结果自动添加的伪列,第一行是1,如果where rownum>2,这时候查找第一条发现它的rownum=1,不满足条件,于是抛弃掉,把第二条语句的rownum赋值为1,再判断第二条记录是否满足条件,同样不满足。。。。于是发生了死循环一样的判断,最终返回空;
有人这时候就奇怪啦,为什么第一条记录rownum=1不满足条件时候,第二条记录rownum=2,却要重新设值为1呢-----非常简单,你直接在where后添加了条件rownum>2,它是个条件啦,第一条记录不满足条件,叫抛弃掉啦,这时候结果集是空的,当然会一直rownum=1的赋值;
解决办法:先查询,并为每条记录分配rownum,然后嵌套查询
select t.* from (select rownum num,id,name from student) t where t.num>2
第二条语句可以正常的执行,根据上面的解释,这个可以理解了吧!
2.rownum与order by同时存在的问题
当 where 后面有rownum的判断,并且存在order by时候,rownum的优先级高!
oracle会先执行rownum的判断,然后从结果中order by,很明显是错误的结果啦!就好像学校要取成绩最好的前10名同学,结果这种方法一执行,成了取出10名同学,然后按照成绩的高低排序!
这点与SQL Server的TOP完全不同,TOP遇上order by,是先执行order by,在分页的;
解决办法就是先执行order by,然后嵌套执行rownum-----说白啦就是用()改变函数的优先级!
Oracle的分页查询语句基本上可以按照本文给出的格式来进行套用。
分页查询格式:
SELECT * FROM
(
SELECT A.*, ROWNUM RN
FROM (SELECT * FROM TABLE_NAME) A
WHERE ROWNUM <= 40
)
WHERE RN >= 21
其中最内层的查询SELECT * FROM TABLE_NAME表示不进行翻页的原始查询语句。ROWNUM <= 40和RN >= 21控制分页查询的每页的范围。
上面给出的这个分页查询语句,在大多数情况拥有较高的效率。分页的目的就是控制输出结果集大小,将结果尽快的返回。在上面的分页查询语句中,这种考虑主要体现在WHERE ROWNUM <= 40这句上。
选择第21到40条记录存在两种方法,一种是上面例子中展示的在查询的第二层通过ROWNUM <= 40来控制最大值,在查询的最外层控制最小值。而另一种方式是去掉查询第二层的WHERE ROWNUM <= 40语句,在查询的最外层控制分页的最小值和最大值。这是,查询语句如下:
SELECT * FROM
(
SELECT A.*, ROWNUM RN
FROM (SELECT * FROM TABLE_NAME) A
)
WHERE RN BETWEEN 21 AND 40
对比这两种写法,绝大多数的情况下,第一个查询的效率比第二个高得多。
这是由于CBO优化模式下,Oracle可以将外层的查询条件推到内层查询中,以提高内层查询的执行效率。对于第一个查询语句,第二层的查询条件WHERE ROWNUM <= 40就可以被Oracle推入到内层查询中,这样Oracle查询的结果一旦超过了ROWNUM限制条件,就终止查询将结果返回了。
而第二个查询语句,由于查询条件BETWEEN 21 AND 40是存在于查询的第三层,而Oracle无法将第三层的查询条件推到最内层(即使推到最内层也没有意义,因为最内层查询不知道RN代表什么)。因此,对于第二个查询语句,Oracle最内层返回给中间层的是所有满足条件的数据,而中间层返回给最外层的也是所有数据。数据的过滤在最外层完成,显然这个效率要比第一个查询低得多。
上面分析的查询不仅仅是针对单表的简单查询,对于最内层查询是复杂的多表联合查询或最内层查询包含排序的情况一样有效。
这里就不对包含排序的查询进行说明了,下一篇文章会通过例子来详细说明。下面简单讨论一下多表联合的情况。对于最常见的等值表连接查询,CBO一般可能会采用两种连接方式NESTED LOOP和HASH JOIN(MERGE JOIN效率比HASH JOIN效率低,一般CBO不会考虑)。在这里,由于使用了分页,因此指定了一个返回的最大记录数,NESTED LOOP在返回记录数超过最大值时可以马上停止并将结果返回给中间层,而HASH JOIN必须处理完所有结果集(MERGE JOIN也是)。那么在大部分的情况下,对于分页查询选择NESTED LOOP作为查询的连接方法具有较高的效率(分页查询的时候绝大部分的情况是查询前几页的数据,越靠后面的页数访问几率越小)。
因此,如果不介意在系统中使用HINT的话,可以将分页的查询语句改写为:
SELECT /*+ FIRST_ROWS */ * FROM
(
SELECT A.*, ROWNUM RN
FROM (SELECT * FROM TABLE_NAME) A
WHERE ROWNUM <= 40
)
WHERE RN >= 21
其他方法列举:
该语句实现了从第301条记录开始处取600条记录:
select * from t_table where rowid not in(select rowid from t_table where rownum<=300) and rownum<=300
SELECT * FROM table WHERE ROWNUM<=600
minus
SELECT * FROM table WHERE ROWNUM<=300;
效率需要测试的。
转载自:
http://oracle.chinaitlab.com/exploiture/833216.html
http://space.itpub.net/756652/viewspace-242185