Oracle中rownum的用法解析

标签: oracle rownum 解析 | 发表时间:2013-04-10 10:27 | 作者:xueshuangshuang123
出处:http://blog.csdn.net

对于rownum来说它是oracle系统顺序分配为从查询返回的行的编号,返回的第一行分配的是1,第二行是2,依此类推,这个伪字段可以用于限制查询返回的总行数,且rownum不能以任何表的名称作为前缀。

(1) rownum 对于等于某值的查询条件
如果希望找到学生表中第一条学生的信息,可以使用rownum=1作为条件。但是想找到学生表中第二条学生的信息,使用rownum=2结果查不到数据。因为rownum都是从1开始,但是1以上的自然数在rownum做等于判断是时认为都是false条件,所以无法查到rownum = n(n>1的自然数)。
SQL> select rownum,id,name from student where rownum=1;(可以用在限制返回记录条数的地方,保证不出错,如:隐式游标)
SQL> select rownum,id,name from student where rownum =2; 
    ROWNUM ID     NAME
---------- ------ ---------------------------------------------------

(2)rownum对于大于某值的查询条件
   如果想找到从第二行记录以后的记录,当使用rownum>2是查不出记录的,原因是由于rownum是一个总是从1开始的伪列,Oracle 认为rownum> n(n>1的自然数)这种条件依旧不成立,所以查不到记录。

查找到第二行以后的记录可使用以下的子查询方法来解决。注意子查询中的rownum必须要有别名,否则还是不会查出记录来,这是因为rownum不是某个表的列,如果不起别名的话,无法知道rownum是子查询的列还是主查询的列。
SQL>select * from(select rownum no ,id,name from student) where no>2;
        NO ID     NAME
---------- ------ ---------------------------------------------------
         3 200003 李三
         4 200004 赵四

(3)rownum对于小于某值的查询条件
rownum对于rownum<n((n>1的自然数)的条件认为是成立的,所以可以找到记录。
SQL> select rownum,id,name from student where rownum <3;
    ROWNUM ID     NAME
---------- ------ ---------------------------------------------------
        1 200001 张一
        2 200002 王二

查询rownum在某区间的数据,必须使用子查询。例如要查询rownum在第二行到第三行之间的数据,包括第二行和第三行数据,那么我们只能写以下语句,先让它返回小于等于三的记录行,然后在主查询中判断新的rownum的别名列大于等于二的记录行。但是这样的操作会在大数据集中影响速度。
SQL> select * from (select rownum no,id,name from student where rownum<=3 ) where no >=2;
        NO ID     NAME
---------- ------ ---------------------------------------------------
         2 200002 王二
         3 200003 李三

(4)rownum和排序   
Oracle中的rownum的是在取数据的时候产生的序号,所以想对指定排序的数据去指定的rowmun行数据就必须注意了。
SQL> select rownum ,id,name from student order by name;
    ROWNUM ID     NAME
---------- ------ ---------------------------------------------------
         3 200003 李三
         2 200002 王二
         1 200001 张一
         4 200004 赵四
可以看出,rownum并不是按照name列来生成的序号。系统是按照记录插入时的顺序给记录排的号,rowid也是顺序分配的。为了解决这个问题,必须使用子查询;
SQL> select rownum ,id,name from (select * from student order by name);
    ROWNUM ID     NAME
---------- ------ ---------------------------------------------------
         1 200003 李三
         2 200002 王二
         3 200001 张一
         4 200004 赵四
这样就成了按name排序,并且用rownum标出正确序号(有小到大)
笔者在工作中有一上百万条记录的表,在jsp页面中需对该表进行分页显示,便考虑用rownum来作,下面是具体方法(每页显示20条): 
“select * from tabname where rownum<20 order by name" 但却发现oracle却不能按自己的意愿来执行,而是先随便取20条记录,然后再order by,后经咨询oracle,说rownum确实就这样,想用的话,只能用子查询来实现先排序,后rownum,方法如下: 
"select * from (select * from tabname order by name) where rownum<20",但这样一来,效率会低很多。 
后经笔者试验,只需在order by 的字段上加主键或索引即可让oracle先按该字段排序,然后再rownum;方法不变:    “select * from tabname where rownum<20 order by name"

取得某列中第N大的行

select column_name from 
(select table_name.*,dense_rank() over (order by column desc) rank from table_name) 
where rank = &N; 
 假如要返回前5条记录:

  select * from tablename where rownum<6;(或是rownum <= 5 或是rownum != 6) 
假如要返回第5-9条记录:

select * from tablename 
where … 
and rownum<10 
minus 
select * from tablename 
where … 
and rownum<5 
order by name 
选出结果后用name排序显示结果。(先选再排序)

注意:只能用以上符号(<、<=、!=)。

select * from tablename where rownum != 10;返回的是前9条记录。 
不能用:>,>=,=,Between...and。由于rownum是一个总是从1开始的伪列,Oracle 认为这种条件不成立。

另外,这个方法更快:

select * from ( 
select rownum r,a from yourtable 
where rownum <= 20 
order by name ) 
where r > 10 
这样取出第11-20条记录!(先选再排序再选)

要先排序再选则须用select嵌套:内层排序外层选。 
rownum是随着结果集生成的,一旦生成,就不会变化了;同时,生成的结果是依次递加的,没有1就永远不会有2! 
rownum 是在查询集合产生的过程中产生的伪列,并且如果where条件中存在 rownum 条件的话,则:

1: 假如判定条件是常量,则: 
只能 rownum = 1, <= 大于1 的自然数, = 大于1 的数是没有结果的;大于一个数也是没有结果的 
即 当出现一个 rownum 不满足条件的时候则 查询结束 this is stop key(一个不满足,系统将该记录过滤掉,则下一条记录的rownum还是这个,所以后面的就不再有满足记录,this is stop key);

2: 假如判定值不是常量,则:

若条件是 = var , 则只有当 var 为1 的时候才满足条件,这个时候不存在 stop key ,必须进行full scan ,对每个满足其他where条件的数据进行判定,选出一行后才能去选rownum=2的行……

以下摘自《中国IT实验室》

1.在ORACLE中实现SELECT TOP N 

   由于ORACLE不支持SELECT TOP语句,所以在ORACLE中经常是用ORDER BY跟ROWNUM的组合来实现SELECT TOP N的查询。

简单地说,实现方法如下所示: 

SELECT 列名1...列名n FROM 

    (SELECT 列名1...列名n FROM 表名 ORDER BY 列名1...列名n) 

   WHERE ROWNUM <= N(抽出记录数) 

ORDER BY ROWNUM ASC 

   下面举个例子简单说明一下。

顾客表customer(id,name)有如下数据:

ID NAME 

   01 first

   02 Second

   03 third

   04 forth

   05 fifth

   06 sixth

   07 seventh

   08 eighth

   09 ninth

   10 tenth

   11 last 

   则按NAME的字母顺抽出前三个顾客的SQL语句如下所示:

SELECT * FROM 

    (SELECT * FROM CUSTOMER ORDER BY NAME) 

   WHERE ROWNUM <= 3 

   ORDER BY ROWNUM ASC 

   输出结果为:

ID NAME

   08 eighth

   05 fifth

   01 first 

2.在TOP N纪录中抽出第M(M <= N)条记录

ROWNUM是记录表中数据编号的一个隐藏子段,所以可以在得到TOP N条记录的时候同时抽出记录的ROWNUM,然后再从这N条记录中抽取记录编号为M的记录,即使我们希望得到的结果。

从上面的分析可以很容易得到下面的SQL语句。 

SELECT 列名1...列名n FROM 

     ( 

     SELECT ROWNUM RECNO, 列名1...列名nFROM 

       (SELECT 列名1...列名n FROM 表名 ORDER BY 列名1...列名n) 

     WHERE ROWNUM <= N(抽出记录数) 

   ORDER BY ROWNUM ASC 

     ) 

   WHERE RECNO = M(M <= N)

同样以上表的数据为基础,那么得到以NAME的字母顺排序的第二个顾客的信息的SQL语句应该这样写:

   SELECT ID, NAME FROM 

     ( 

      SELECT ROWNUM RECNO, ID, NAME FROM 

        (SELECT * FROM CUSTOMER ORDER BY NAME) 

         WHERE ROWNUM <= 3 

         ORDER BY ROWNUM ASC ) 

       WHERE RECNO = 2 

     结果则为:

   ID NAME

    05 fifth 

3.抽出按某种方式排序的记录集中的第N条记录

   在2的说明中,当M = N的时候,即为我们的标题讲的结果。实际上,2的做法在里面N>M的部分的数据是基本上不会用到的,我们仅仅是为了说明方便而采用。

   如上所述,则SQL语句应为:

SELECT 列名1...列名n FROM 

     ( 

      SELECT ROWNUM RECNO, 列名1...列名nFROM 

        (SELECT 列名1...列名n FROM 表名 ORDER BY 列名1...列名n) 

         WHERE ROWNUM <= N(抽出记录数) 

      ORDER BY ROWNUM ASC 

     ) 

     WHERE RECNO = N 

     那么,2中的例子的SQL语句则为:

    SELECT ID, NAME FROM 

      ( 

       SELECT ROWNUM RECNO, ID, NAME FROM 

         (SELECT * FROM CUSTOMER ORDER BY NAME) 

       WHERE ROWNUM <= 2 

       ORDER BY ROWNUM ASC 

      ) 

      WHERE RECNO = 2 

     结果为:

   ID NAME

    05 fifth 

4.抽出按某种方式排序的记录集中的第M条记录开始的X条记录

   3里所讲得仅仅是抽取一条记录的情况,当我们需要抽取多条记录的时候,此时在2中的N的取值应该是在N >= (M + X - 1)这个范围内,当让最经济的取值就是取等好的时候了的时候了。当然最后的抽取条件也不是RECNO = N了,应该是RECNO BETWEEN M AND (M + X - 1)了,所以随之而来的SQL语句则为:

   SELECT 列名1...列名n FROM 

    ( 

     SELECT ROWNUM RECNO, 列名1...列名nFROM 

      (

      SELECT 列名1...列名n FROM 表名 ORDER BY 列名1...列名n) 

      WHERE ROWNUM <= N (N >= (M + X - 1)) 

    ORDER BY ROWNUM ASC 

      ) 

     WHERE RECNO BETWEEN M AND (M + X - 1) 

    同样以上面的数据为例,则抽取NAME的字母顺的第2条记录开始的3条记录的SQL语句为:

   SELECT ID, NAME FROM 

     ( 

      SELECT ROWNUM RECNO, ID, NAME FROM 

        (SELECT * FROM CUSTOMER ORDER BY NAME) 

      WHERE ROWNUM <= (2 + 3 - 1) 

      ORDER BY ROWNUM ASC 

     ) 

     WHERE RECNO BETWEEN 2 AND (2 + 3 - 1) 

     结果如下:

   ID NAME

    05 fifth

    01 first

   04 forth 

    以此为基础,再扩展的话,做成存储过程,将开始记录数以及抽取记录数为参数,就可以轻松实现分页抽取数据。

   当然了,上面所讲的都是一些最基本的,实际应用中往往都没有这么简单,但是不管怎么说,不管复杂的应用总是由这些简单的元素构成,掌握一些最基本的方法始终是重要的。

作者:xueshuangshuang123 发表于2013-4-10 10:27:02 原文链接
阅读:57 评论:0 查看评论

相关 [oracle rownum 解析] 推荐:

Oracle中rownum的用法解析

- - CSDN博客数据库推荐文章
对于rownum来说它是oracle系统顺序分配为从查询返回的行的编号,返回的第一行分配的是1,第二行是2,依此类推,这个伪字段可以用于限制查询返回的总行数,且rownum不能以任何表的名称作为前缀. (1) rownum 对于等于某值的查询条件. 如果希望找到学生表中第一条学生的信息,可以使用rownum=1作为条件.

Oracle rownum影响执行计划

- - CSDN博客数据库推荐文章
   今天调优一条SQL语句,由于SQL比较复杂,用autotrace很难一眼看出哪里出了问题,直接上10046.                                   N.TECH_OBJECT_NODE_ID = N.PARENT_ID) TAB.                                   N.TECH_OBJECT_NODE_ID = N.PARENT_ID) TAB.

彻底弄懂oracle硬解析、软解析、软软解析

- - CSDN博客数据库推荐文章
     硬解析和软解析有相同的一步,而软软解析与硬解析、软解析完全不一样. 先来说下理论上的东西,然后来做个实验.     1.语法、语义及权限检查;.     2.查询转换(通过应用各种不同的转换技巧,会生成语义上等同的新的SQL语句,如count(1)会转为count(*));.     3.根据统计信息生成执行计划(找出成本最低的路径,这一步比较耗时);.

<转>Oracle中的软解析和硬解析

- - Oracle - 数据库 - ITeye博客
原链接: http://soft.chinabyte.com/database/468/12178468.shtml. shared pool设置不合理除了命中率低外还有哪些现象.   说到软解析(soft prase)和硬解析(hard prase),就不能不说一下Oracle对sql的处理过程.

Oracle直接路径加载--append的深度解析

- - CSDN博客推荐文章
        ㈠ 直接路径加载和buffer cache.        直接路径插入的数据不经过buffer cache,从PGA直接把数据格式化成Oracle块.        然后由普通的Oracle Server Process进程把数据块写入数据文件.        因为不经过buffer cache,所以不需要DBWn介入.

Oracle 收购 Ksplice

- feng823 - LinuxTOY
实现无需重启即可为 Linux 内核打安全补丁的 Ksplice 被 Oracle 收购. 在被收购前, Ksplice 为 Fedora, Ubuntu 免费提供该功能,对于 RHEL 和 CentOS 则需要订阅其产品. Oracle 表示将把 Ksplice 带来的零宕机安全更新功能添加到 Oracle 产品订阅服务中,同时停止对其他企业级 Linux 发行版的支持,将 Oracle Unbreakable Linux 打造成唯一具备零宕机安全更新功能的企业级 Linux 发行版.

Linux Ksplice,MySQL and Oracle

- Syn - DBA Notes
Oracle 在 7 月份收购了 Ksplice. 使用了 Ksplice 的 Linux 系统,为 Kernel 打补丁无需重启动,做系统维护的朋友应该明白这是一个杀手级特性. 现在该产品已经合并到 Oracle Linux 中. 目前已经有超过 700 家客户,超过 10 万套系统使用了 Ksplice (不知道国内是否已经有用户了.

oracle license计算

- Fenng - eagle&#39;s home
Oracle license的计算是基于CPU core的. 用core的数目乘以一个系数core factor就可以得到所需的oracle license的数目. 对于不同的CPU,core factor是不一样的,可以从oracle提供的这张列表中查到 Oracle Processor Core Factor Table.

Oracle Exadata初探

- - 技术改变世界 创新驱动中国 - 《程序员》官网
在我们看来,它是一个把硬件和软件根据合理的配置整合在一起的 Oracle数据库(在本文编写时是11gR2版本)平台. Exadata数据库机器包含了存储子系统,在存储层上运行着研发的新软件,这使得研发人员可以做一些在其他平台上无法完成的事情. 实际上,Exadata一开始是以一个存储系统形式诞生的,如果你跟参与研发此产品的人交谈,你经常会听到他们称存储组件为Exadata或者是SAGE (Storage Appliance for Grid Environments,网格环境存储设备),这是该产品研发项目的代码名称.

Oracle MySQL Or NoSQL续

- - Sky.Jian 朝阳的天空
接前面一篇,这里再将之前在“中国系统架构师大会”5周年的时候发布的纪念册“IT架构实录”上的一篇文章发出来,也算是前面博文中PPT的一个文字版解读吧. Oracle,MySQL 还是 NoSQL. 随着阿里系的“去IOE”运动在社区的宣传声越来越大,国内正在掀起一股“去xxx”的技术潮. 不仅仅是互联网企业,包括运营商以及金融机构都已经开始加入到这个潮流之中.