我们知道。rowid和rownum在Oracle中都是能够被当做伪劣使用的,主要用来定位表中特定的记录,但它们是有差别的,rowid是和行记录的物理地址相应的。而rownum则不是,是通过返回的记录集来推断首条记录,即rownum=1的记录,然后再去fetch之后的记录。rownum=2、rownum=3……,以此类推。以下来看实验:

SQL> conn zlm/zlm
Connected.
SQL> create table test1 as select object_id,object_name from dba_objects where rownum<11;

Table created.

注意,创建表的时候,也用到了rownum<11这个伪列上的where条件,获取到10条记录插入到test1表。

SQL> set lin 130 pages 130
SQL> col object_name for a30
SQL> select * from test1;

 OBJECT_ID OBJECT_NAME
---------- ------------------------------
        20 ICOL$
        44 I_USER1
        28 CON$
        15 UNDO$
        29 C_COBJ#
         3 I_OBJ#
        25 PROXY_ROLE_DATA$
        39 I_IND1
        51 I_CDEF2
        26 I_PROXY_ROLE_DATA$_1

10 rows selected.

用*来表示所有列。此时并不会显示出rowid,rownum这2个伪列,这也就是“伪列”这个名词的由来。是假的,fake的,我们能够使用它。但并不作为数据存储在表中

SQL> select rowid,rownum,object_id,object_name from test1;

ROWID                  ROWNUM  OBJECT_ID OBJECT_NAME
------------------ ---------- ---------- ------------------------------
AAAM+rAAGAAAACUAAA          1         20 ICOL$
AAAM+rAAGAAAACUAAB          2         44 I_USER1
AAAM+rAAGAAAACUAAC          3         28 CON$
AAAM+rAAGAAAACUAAD          4         15 UNDO$
AAAM+rAAGAAAACUAAE          5         29 C_COBJ#
AAAM+rAAGAAAACUAAF          6          3 I_OBJ#
AAAM+rAAGAAAACUAAG          7         25 PROXY_ROLE_DATA$
AAAM+rAAGAAAACUAAH          8         39 I_IND1
AAAM+rAAGAAAACUAAI          9         51 I_CDEF2
AAAM+rAAGAAAACUAAJ         10         26 I_PROXY_ROLE_DATA$_1

10 rows selected.

把列名所有显示指定。能够看到,rowid和rownum这两列的内容也都显示了。那我们能不能用rowid列来作为查找条件呢?当然是能够的,但前提是你要知道rowid值是怎么分布的

SQL> select rowid,object_id,object_name from test1 where rowid<to_char('AAAM+rAAGAAAACUAAK');

ROWID               OBJECT_ID OBJECT_NAME
------------------ ---------- ------------------------------
AAAM+rAAGAAAACUAAA         20 ICOL$
AAAM+rAAGAAAACUAAB         44 I_USER1
AAAM+rAAGAAAACUAAC         28 CON$
AAAM+rAAGAAAACUAAD         15 UNDO$
AAAM+rAAGAAAACUAAE         29 C_COBJ#
AAAM+rAAGAAAACUAAF          3 I_OBJ#
AAAM+rAAGAAAACUAAG         25 PROXY_ROLE_DATA$
AAAM+rAAGAAAACUAAH         39 I_IND1
AAAM+rAAGAAAACUAAI         51 I_CDEF2
AAAM+rAAGAAAACUAAJ         26 I_PROXY_ROLE_DATA$_1

10 rows selected.

为什么条件是<to_char('AAAM+rAAGAAAACUAAK')?由于通过刚才的观察,我们知道test1表中的第10条记录是到J。那么要获取这10条记录,就是比AAK小的这些记录

这里来说明一下rowid中这些字母表示的含义:

在Oracle 8下面,rowid(也叫受限rowid)为:FFFF.BBBBBBBB.RRRR,占用6个字节(10bit file#+22bit+16bit)。可是,为了扩充的须要,如数据文件的扩充,如今的rowid改为:OOOOOOFFFBBBBBBRRR。占用10个字节(32bit+10bit
rfile#+22bit+16bit)。

当中,O是Object号,F是File号,B是Block号。R是Row号。

由于rowid的组成从file#变成了rfile#。所以数据文件数的限制也从整个库不能超过1023个变成了每一个表空间不能超过1023个数据文件。这里的object_id,是与段物理存储位置相关的一个信息。由于一个段对象仅仅可能在一个表空间上,object_id能唯一确认ts#,而object_id
+ rfile#就能终于定位到该rowid在哪个确定的物理数据文件上


因此。这里的AAG就表示这是第6个数据文件。要注意的是。AAA从0開始计数,行号也是如此。

因此,AAA-AAJ就表示是test1表中的1-10行记录(0->9)


SQL> col name for a45
SQL> select file#,name from v$datafile;

     FILE# NAME
---------- ---------------------------------------------
         1 /u01/app/oracle/oradata/ora10g/system01.dbf
         2 /u01/app/oracle/oradata/ora10g/undotbs01.dbf
         3 /u01/app/oracle/oradata/ora10g/sysaux01.dbf
         4 /u01/app/oracle/oradata/ora10g/users01.dbf
         5 /u01/app/oracle/oradata/ora10g/example01.dbf
         6 /u01/app/oracle/oradata/ora10g/zlm01.dbf

zlm用户默认的表空间就是zlm,其相应的数据文件就是zlm01.dbf,能够看到。file#为6而并非7

我们还能够用Oracle提供的dbms.rowid包来依据rowid的值来获取object_id#。rfile#,block#。row#这些详细的值:

SQL> select dbms_rowid.rowid_object('AAAM+rAAGAAAACUAAJ') object_id#,dbms_rowid.rowid_relative_fno('AAAM+rAAGAAAACUAAJ') rfile#,dbms_rowid.rowid_block_number('AAAM+rAAGAAAACUAAJ')
block#,dbms_rowid.rowid_row_number('AAAM+rAAGAAAACUAAJ') row# from dual;

OBJECT_ID#     RFILE#     BLOCK#       ROW#
--------------- ---------- ---------- ----------
          53163          6        148          9

test1表中第10行记录就是第53163个对象、第6号文件、第148个块的第10条记录(0->9)

假设我们要获取test1表中的前5条记录。那么能够用例如以下的方法:

SQL> select object_id,object_name from test1 where rownum<=5;

 OBJECT_ID OBJECT_NAME
---------- ------------------------------
        20 ICOL$
        44 I_USER1
        28 CON$
        15 UNDO$
        29 C_COBJ#

或者

SQL> select object_id,object_name from test1 where rownum!=6;

 OBJECT_ID OBJECT_NAME
---------- ------------------------------
        20 ICOL$
        44 I_USER1
        28 CON$
        15 UNDO$
        29 C_COBJ#

对于第一种写法。大家都能够理解。那么为什么rownum!=6这个条件。返回的也是前5条记录呢?是不是认为不可思议。7-10条记录也满足!=6啊,为什么不会显示呢?

来看一下官方关于rowid机制的解释:

1 Oracle executes your query.

2 Oracle fetches the first row and calls it row number 1.

3 Have we gotten past row number meets the criteria? If no, then Oracle discards the row, If yes, then Oracle return the row.

4 Oracle fetches the next row and advances the row number (to 2, and then to 3, and then to 4, and so forth).

5 Go to step 3.

当你使用rownum作为查询条件是,Oracle的SQL引擎总是会先去找row number 1这条记录。假设没有找到,那么就直接丢弃这些row,直到找到为止,然后才会有row number 2,row number 3……不断地循环这个过程,直到结束不符合条件为止

在第2个查询中,因为rownum=1符合了!=6这个条件。那么会依次fetch下去,直到取到了rownum=5,都是符合的记录。然后就会返回一个结果。而因为中间断档了。那么当找到第6条记录的时候,显然不符合!=6这个条件。那么刚才的一轮循环就结束了,而之后的第7条记录,因为当中不再包括row numer 1这个必要条件,因此直接就丢弃了后面的查询,也就是说。8-10条记录也不会再去fetch了。因为没有一条能够获取到rownum=1

相同的,当我们要获取后5条记录。即5<rownum<11的记录,直接使用下面查询是获取不到值的:

SQL> select rownum,object_id,object_name from test1 where rownum>5 and rownum <11;

no rows selected

为什么呢?原因刚才已经解释过了,由于rownum>5中首先就排除掉了rownum=1这条记录。因此就直接丢弃这些行,也就没有返回结果了,也就是一直去找row number 1,但永远也找不到(由于被条件排除掉了),即使把rownum<11这个条件写在前面,结果也是一致的。注意这里连接条件用的是and。假设用or那就相当于把rownum>5这个条件忽略了。是会有结果的

SQL> select object_id,object_name from test1 where rownum<11 or rownum>5;

 OBJECT_ID OBJECT_NAME
---------- ------------------------------
        20 ICOL$
        44 I_USER1
        28 CON$
        15 UNDO$
        29 C_COBJ#
         3 I_OBJ#
        25 PROXY_ROLE_DATA$
        39 I_IND1
        51 I_CDEF2
        26 I_PROXY_ROLE_DATA$_1

10 rows selected.

即使使用between ... and ...也是不行的,看运行结果:

SQL> select object_id,object_name from test1 where rownum between 0 and 5;

 OBJECT_ID OBJECT_NAME
---------- ------------------------------
        20 ICOL$
        44 I_USER1
        28 CON$
        15 UNDO$
        29 C_COBJ#

SQL> select object_id,object_name from test1 where rownum between 1 and 5;

 OBJECT_ID OBJECT_NAME
---------- ------------------------------
        20 ICOL$
        44 I_USER1
        28 CON$
        15 UNDO$
        29 C_COBJ#

SQL> select object_id,object_name from test1 where rownum between 6 and 10;

no rows selected

between0和1都是包括有rownum=1的,因此有结果。而between 6就相当于直接rownum>5,把rownum=1排除掉了,所以就无结果

因为rownum的这个伪列的特殊性,因此在我们书写SQL语句时,尤其是写分页代码的时候。必须使用子查询来获取后5条记录,如:

SQL> select b.object_id,b.object_name from (select rownum rn,a.* from test1 a where rownum<11) b where rn>5;

 OBJECT_ID OBJECT_NAME
---------- ------------------------------
         3 I_OBJ#
        25 PROXY_ROLE_DATA$
        39 I_IND1
        51 I_CDEF2
        26 I_PROXY_ROLE_DATA$_1

当然。我们也能够用rowid来直接获取后5条记录,由于rowid没有rownum那样的特殊要求。但实际操作起来。是很不方便的,实际环境中也没有这种使用方法,rowid难以记忆也不方便书写

SQL> select object_id,object_name from test1 where rowid>to_char('AAAM+rAAGAAAACUAAE') and rowid<=to_char('AAAM+rAAGAAAACUAAJ');

 OBJECT_ID OBJECT_NAME
---------- ------------------------------
         3 I_OBJ#
        25 PROXY_ROLE_DATA$
        39 I_IND1
        51 I_CDEF2
        26 I_PROXY_ROLE_DATA$_1

总结:

rowid通常不直接用于SQL代码中。主要是给索引使用的。通过索引查找rowid,再更具rowid回表取数据,使Oracle数据库完毕高效的数据检索,而rownum则经经常使用在数据库的应用代码中,尤其是对分页数据的过滤,但使用的时候必需要注意rownum的特性。切忌跳过对rownum=1的获取而造成无结果集的问题










使用rowid和rownum获取记录时要注意的问题的更多相关文章

  1. oracle_SQL中ROWID与ROWNUM的使用(转)

    转自:http://www.360doc.com/content/12/0802/11/219024_227802569.shtml rownum: ROWNUM是对结果集加的一个伪列, 即先查到结果 ...

  2. 讨论oracle在rowid和rownum

    [ 概要 ] 刚刚接触oracle的同学可能经常会被rowid和rownum这两个词弄混, 弄清楚这两个家伙对于我们写sql会有非常大的帮助, 以下偶就抛砖引玉, 简单地谈谈他们之间的差别吧. [ 比 ...

  3. Oracle的RowId和Rownum

    本文参照来自:https://www.cnblogs.com/whut-helin/p/8024860.html 由sql select p.*,rowid,rownum from promotion ...

  4. ObjectStore onFetch方法获取记录总数

    转自:http://blog.csdn.net/earthhour/article/details/38686029 ObjectStore onFetch方法获取记录总数 require(['doj ...

  5. oracle 的rowid和rownum

    rowid就是唯一标志记录物理位置的一个id,对于rownum来说它是oracle系统顺序分配为从查询返回的行的编号,返回的第一行分配的是1,第二行是2,依此类推,这个伪字段可以用于限制查询返回的总行 ...

  6. mybatis添加记录时返回主键id

    参考:mybatis添加记录时返回主键id 场景 有些时候我们在添加记录成功后希望能直接获取到该记录的主键id值,而不需要再执行一次查询操作.在使用mybatis作为ORM组件时,可以很方便地达到这个 ...

  7. 使用mybatis注解@Options实现添加记录时返回主键值

    官网:http://www.mybatis.org/mybatis-3/index.html 在使用mybatis作为ORM框架时,我通常更喜欢使用注解而非xml配置文件的方式.业务场景:添加记录之后 ...

  8. Oracle-12:伪列rowid和rownum

    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 伪列:不真实存储在真表中,但是我们可以查询到不能对伪列进行增删改操作! 分页可以用rownum来分!!!!!! ...

  9. thinkphp5 数据库查询之paginate: 同时获取记录总数和分页数据

    thinkphp5中要想同时获得查询记录的总数量以及分页的数据, 可以用paginate(), 真的非常方便! 表结构: CREATE TABLE `t_users` ( `id` int(11) u ...

随机推荐

  1. Linux查看网卡状态

    观看网卡传送.接收数据包的状态 $ netstat  -i Kernel Interface table Iface MTU Met RX-OK RX-ERR RX-DRP RX-OVR TX-OK ...

  2. Oracle EBS-SQL (PO-3):检查期间手工下达的采购订单记录数.sql

    SELECT DECODE(pda.req_distribution_id,'','手工','自动创建') 下达方式, --pda.req_distribution_id                ...

  3. ECO

    ECO(生态环保的简写) 在与环保相关的概念和资料中,ECO 是ECOLOGICAL的缩写,用来表示生态环保的意思.与之相关产生了一些新的名词,尤其是在房地产楼书中常常被提及,如: ECO-HOME, ...

  4. ASP 代码当前记录集不支持更新问题的解决办法。

    错误类型: ADODB.Recordset (0x800A0CB3) 当前记录集不支持更新.这可能是提供程序的限制,也可能是选定锁定类型的限制. /Model/manage/Admin_Admin.a ...

  5. perl 正则命名捕获

    #!/usr/bin/perl -w =pod 命名捕获--给匹配上的内容加上标签 捕获到的内容都会保存在%+散列中,这个散列的key为对应的标签: 方便之处就是利于程序扩展和阅读,不用繁琐的一个一个 ...

  6. Gradient boosting

    Gradient boosting gradient boosting 是一种boosting(组合弱学习器得到强学习器)算法中的一种,可以把学习算法(logistic regression,deci ...

  7. warning C4133: “函数”: 从“char [5]”到“LPCWSTR”的类型不兼容

    弹窗打开一个网页,但是报错,代码如下: #include <stdio.h> #include <windows.h> void main() { ShellExecute(, ...

  8. HTML字符实体(Character Entities),转义字符串(Escape Sequence)【转】

    为什么要用转义字符串? HTML中<,>,&等有特殊含义(<,>,用于链接签,&用于转义),不能直接使用.这些符号是不显示在我们最终看到的网页里的,那如果我们希 ...

  9. sharepoint 2013 reporting services 远程server返回错误: (500) 内部server错误。

    在sharepoint 2013部署reporting services过程中,点击管理中心,server上的服务.系统配置.提示了一个错误: 远程server返回错误: (500) 内部server ...

  10. 教你如何利用初级C#语言更改银行存款!!!!

    您是否对生活现状不满意? 您是否总是感叹工资太少? 您是否经常发现自己相中的物品又降价了然而自己却还是只能望洋兴叹? 没关系!让我来拯救你的钱包! 接下来进入正题: 要想更改自己的银行存款首先得找到一 ...