Oracle中rownum用法
rownum的说明
rownum是oracle特有的一个关键字。
对于基表,在insert记录时,oracle就按照insert的顺序,将rownum分配给每一行记录,因此在select一个基表的时候,rownum的排序是根据insert记录的顺序显示的。例如:
select rownum rn,t.* from emp t;
对于子查询,则rownum的顺序是根据子查询的查询顺序进行动态分配的,例如:
select rownum as t2_rn, t2.*
from (select rownum as t1_rn, t1.* from emp t1 order by t1.sal) t2;
由上图可以看到T1_RN和T2_RN的区别。
t1中的rownum是根据emp这个基表的默认顺序分配的,而内层子循环是根据SAL字段进行排序,所以t2的rownum是根据内层子查询的记录顺序分配的。
rownum可以用于限制返回查询的总行数,且rownum不可以以任何表的名称作为前缀。
1、rownum对于等于某值的查询条件:如果想找到第一条查询数据,可以使用rownum=1作为查询条件,但是想找到第二条查询数据,使用rownum=2则查不到数据,原因是:rownum都是从1开始,但是1以上的自然数与rownum做等于时,都认为是false条件,所以无法查询到rownum=n (n>1的自然数);
2、rownum对于大于某值的查询条件:要是想查询出第二行以后的记录,直接使用rownum>2是查不出数据的,原因是rownum是一个总是以1开始的伪例,rownum>n (n>1的自然数)依然不成立。可以使用子查询来解决,注意子查询中的rownum必须要有别名,否则还是不会查出记录来,这是因为rownum不是某个表的列,如果不起别名的话,无法知道rownum是子查询的列还是主查询的列。例如:
select * from(select rownum no ,id,name from student) where no>2;
3、rownum对于小于某值的查询条件: rownum对于rownum<n((n>1的自然数)的条件认为是成立的,所以可以找到记录。
注意:对于查询rownum在某区间的数据,必须使用子查询,例如要查询rownum在第二行到第三行之间的数据,包括第二行和第三行数据,那么我们只能写以下语句,先让它返回小于等于三的记录行,然后在主查询中判断新的rownum的别名列大于等于二的记录行。但是这样的操作会在大数据集中影响速度。
select * from (selectrownum no,id,name from student where rownum<=3 ) where no >=2
4、rownum和排序 Oracle中的rownum的是在取数据的时候产生的序号,所以想对指定排序的数据去指定的rowmun行数据就必须注意了。
select rownum ,id,name from student order by name;
对于这个查询语句,rownum并不是按name生成的序号,系统是按照记录插入时的顺序给记录排的号,rowid也是顺序分配的。为了解决这个问题,必须使用子查询:
select rownum ,id,name from (select * from student order by name);
rownum的一些使用技巧
场景一:使用rownum限制查询返回的记录数
1、例如,我们现在只想看到emp表中的第一条记录:
select * from emp where rownum=1;
2、现在,我们现在想查看emp中的前2条记录:
select * from emp where rownum<=2;
3、假如我们现在只想查看emp中的第二条记录,又该如何写语句呢?
如果where条件为:rownum=2,来看看查询结果:
发现没有查出任何数据,为什么呢?
因为rownum并不是当作实体数据存放在每一张表中,而是在每一次select查询的时候,根据基表的默认insert顺序由oracle动态分配的,有1才有2,如果rownum没有1,那么2也就没有了意义,所以这个查询就不会有任何结果出来。这个时候我们就需要利用子查询和别名列来实现这个需求:
select *
from (select rownum as rn, t.* from emp t where rownum <= 2)
where rn = 2;
首先通过子查询,取出emp表的前2条记录,并将子查询中的rownum定义为别名rn,然后在外层查询中,使用where条件使rn=2即可,查询出emp表的第二条记录:
几种分页查询SQL语句
效率高的写法
无ORDER BY排序的写法。(效率最高)
(经过测试,此方法成本最低,只嵌套一层,速度最快!即使查询的数据量再大,也几乎不受影响,速度依然!)
SELECT *
FROM (SELECT ROWNUM AS rowno, t.*
FROM emp t
WHERE hire_date BETWEEN TO_DATE('20060501', 'yyyymmdd') AND
TO_DATE('20060731', 'yyyymmdd')
AND ROWNUM <= 20) table_alias
WHERE table_alias.rowno >= 10;
有ORDER BY排序的写法。(效率较高)
(经过测试,此方法随着查询范围的扩大,速度也会越来越慢)
SELECT *
FROM (SELECT tt.*, ROWNUM AS rowno
FROM (SELECT t.*
FROM emp t
WHERE hire_date BETWEEN TO_DATE('20060501', 'yyyymmdd') AND
TO_DATE('20060731', 'yyyymmdd')
ORDER BY create_time DESC, emp_no) tt
WHERE ROWNUM <= 20) table_alias
WHERE table_alias.rowno >= 10;
效率垃圾但又似乎很常用的分页写法
SELECT *
FROM (SELECT ROWNUM AS rowno, t.*
FROM k_task t
WHERE flight_date BETWEEN TO_DATE('20060501', 'yyyymmdd') AND
TO_DATE('20060731', 'yyyymmdd')) table_alias
WHERE table_alias.rowno <= 20
AND table_alias.rowno >= 10;
-- TABLE_ALIAS.ROWNO between 10 and 100;