码迷,mamicode.com
首页 > 数据库 > 详细

oracle中rownum和rowid的区别

时间:2016-04-24 06:08:58      阅读:253      评论:0      收藏:0      [点我收藏+]

标签:

 SQL Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
 
rownum和rowid都是伪列,但是两者的根本是不同的,rownum是根据sql查询出的结果给每行分配一个逻辑编号,所以你的sql不同也就会导致最终rownum不同,但是rowid是物理结构上的,在每条记录insert到数据库中时,都会有一个唯一的物理记录 ,
例如  AAAMgzAAEAAAAAgAAB 7499 ALLEN SALESMAN 7698 1981/2/20 1600.00 300.00 30
这里的AAAMgzAAEAAAAAgAAB物理位置对应了这条记录,这个记录是不会随着sql的改变而改变。
因此,这就导致了他们的使用场景不同了,通常在sql分页时或是查找某一范围内的记录时,我们会使用rownum。
1、rownum
例如:
查找2到10范围内的记录(这里包括2和10的记录)
select *
  
from (select rownum rn, a.* from emp a) t
where t.rn between 2 and 10;

查找前三名的记录
select * from emp a where rownum < 3;这里我们要注意,直接用rownum查找的范围必须要包含1;因为rownum是从1开始记录的,当然你可以把rownum查出来后放在一个虚表中作为这个虚表的字段再根据条件查询。
例如:
select *
  
from (select rownum rn, a.* from emp a) t
where t.rn > 2;这就可以了

2、rowid
我们在处理一张表中重复记录时经常用到他,当然你也可以用一个很原始的方法,就是将有重复记录的表中的数据导到另外一张表中,最后再倒回去。
SQL>create table stu_tmp as select distinctfrom stu;
SQL>truncate table sut;        //清空表记录
SQL>insert into stu select * from stu_tmp;    //将临时表中的数据添加回原表但是要是stu的表数据是百万级或是更大的千万级的,那这样的方法显然是不明智的,因此我们可以根据rowid来处理,rowid具有唯一性,查询时效率是很高的,
例如,学生表中的姓名会有重复的情况,但是学生的学号是不会重复的,如果我们要删除学生表中姓名重复只留学号最大的学生的记录,怎么办呢?
delete from stu a
    
where rowid not  in (select max(rowid)
                          
from stu b
                         
where a.name = b.name
                           
and a.stno < b.stno);
这样就可以了。



1.ROWNUM的使用——TOP-N分析
使用SELECT语句返回的结果集,若希望按特定条件查询前N条记录,可以使用伪列ROWNUM。
ROWNUM是对结果集加的一个伪列,即先查到结果集之后再加上去的一个列 (强调:先要有结果集)。简单的说ROWNUM是符合条件结果的序列号。它总是从1开始排起的。
使用ROWNUM时,只能使用<、<=、!=符号。
 
举例:
student(学生)表,表结构为:
ID       
char(6)      --学号
name    VARCHAR2(10)   --姓名
--建表
create table student (ID char(6), name VARCHAR2(10));
--添加测试记录
insert into student values(‘200001‘,‘张一‘);
insert into student values(‘200002‘,‘王二‘);
insert into student values(‘200003‘,‘李三‘);
insert into student values(‘200004‘,‘赵四‘);
commit;
--测试
SQLselect * from student;
ID     NAME
------ ------------------------
200001 张一
200002 王二
200003 李三
200004 赵四
 
⑴ 
rownum 对于等于某值的查询条件
如果希望找到学生表中第一条学生的信息,可以使用rownum=1作为条件。但是想找到学生表中第二条学生的信息,使用rownum=2结果查不到数据。因为rownum都是从1开始,但是1以上的自然数在rownum做等于判断时认为都是false条件,所以无法查到rownum = n(n>1的自然数)。
SQLselect rownum,id,name from student where rownum=1;
    
ROWNUM ID     NAME
---------- ------ ---------------------------------------------------
         1 200001 张一
 
SQLselect rownum,id,name from student where rownum =2;
未选定行
 
⑵ rownum对于大于某值的查询条件
如果想找到从第二行记录以后的记录,当使用rownum>2是查不出记录的,原因是由于rownum是一个总是从1开始的伪列,Oracle 认为rownum> n(n>1的自然数)这种条件依旧不成立,所以查不到记录。
SQLselect rownum,id,name from student where rownum >2;
未选定行
 
那如何才能找到第二行以后的记录呢?可以使用子查询方法来解决。注意子查询中的rownum必须要有别名,否则还是不会查出记录来,这是因为rownum不是某个表的列,如果不起别名的话,无法知道rownum是子查询的列还是主查询的列。
SQL>select * from(select rownum no ,id,name from student) where no>2;
        
NO ID     NAME
---------- ------ ---------------------------------------------------
         3 200003 李三
         
4 200004 赵四
 
SQLselect * from(select rownum,id,name from student)where rownum>2;
未选定行
 
⑶ rownum对于小于某值的查询条件
如果想找到第三条记录以前的记录,当使用rownum<3是能得到两条记录的。显然rownum对于rownum1的自然数)的条件认为是成立的,所以可以找到记录。
SQLselect rownum,id,name from student where rownum <3;
    
ROWNUM ID     NAME
-------------------- ------ ---------------------------------------------------
1 200001 张一
               
2 200002 王二
 
综上几种情况,可能有时候需要查询rownum在某区间的数据,可以看出rownum对小于某值的查询条件是为true的,rownum对于大于某值的查询条件直接认为是false的,但是可以间接的让它转为认为是true的。那就必须使用子查询。例如要查询rownum在第二行到第三行之间的数据,包括第二行和第三行数据,那么我们可以写以下语句,先让它返回小于等于3的记录行,然后在主查询中判断新的rownum的别名列大于等于2的记录行。但是这样的操作会在大数据集中影响速度。
SQLselect * from (select rownum no,id,name from student where rownum<=3 ) where no >=2;
        
NO ID     NAME
---------- ------ ---------------------------------------------------
         2 200002 王二
         
3 200003 李三
 
⑷ rownum和排序
Oracle中的rownum是在取数据的时候产生的序号,所以想对指定排序的数据指定rowmun行数据就必须注意了。
SQLselect rownum ,id,name from student order by name;
    
ROWNUM ID     NAME
---------- ------ ---------------------------------------------------
         3 200003 李三
         
2 200002 王二
         
1 200001 张一
         
4 200004 赵四
 
可以看出,rownum并不是按照name列来生成的序号。系统是按照记录插入时的顺序给记录排的号,rowid也是顺序分配的。为了解决这个问题,必须使用子查询
SQLselect rownum ,id,name from (select * from student order by name);
    
ROWNUM ID     NAME
---------- ------ ---------------------------------------------------
         1 200003 李三
         
2 200002 王二
         
3 200001 张一
         
4 200004 赵四
 
这样就成了按name排序,并且用rownum标出正确序号(由小到大)。order 
by name 如果name是主键或有索引 ,查询出来的rownum完全按照1,2,3.....的次序。
SQLalter table student add constraint pk_stu primary key(name);
SQLselect rownum ,id,name from student order by name;
ROWNUM ID NAME
---------- ------ ---------------------------------------------------
1 200003 李三
2 200002 王二
3 200001 张一
4 200004 赵四
 
 
2. ROWID的使用——快速删除重复的记录
ROWID是数据的详细地址,通过rowid,oracle可以快速的定位某行具体的数据的位置。
ROWID可以分为物理rowid和逻辑rowid两种。普通的表中的rowid是物理rowid,索引组织表(IOT)的rowid是逻辑rowid。
当表中有大量重复数据时,可以使用ROWID快速删除重复的记录。
举例:
--建表tbl
SQLcreate table stu(no number,name varchar2(10),sex char(2));
--添加测试记录
SQLinsert into stu values(1‘ab‘,’男’);
SQLinsert into stu values(1‘bb‘,’女’);
SQLinsert into stu values(1‘ab‘,’男’);
SQLinsert into stu values(1‘ab‘,’男’);
       
SQL>commit;
 
删除重复记录方法很多,列出两种。
⑴ 通过创建临时表
可以把数据先导入到一个临时表中,然后删除原表的数据,再把数据导回原表,SQL语句如下:
SQL>create table stu_tmp as select distinctfrom stu;
SQL>truncate table sut;                                                   //清空表记录
SQL>insert into stu select * from stu_tmp;                        //将临时表中的数据添加回原表
 
这种方法可以实现需求,但是很明显,对于一个千万级记录的表,这种方法很慢,在生产系统中,这会给系统带来很大的开销,不可行。
 
⑵ 利用rowid结合max或min函数
使用rowid快速唯一确定重复行结合max或min函数来实现删除重复行。
SQL>delete from stu a where rowid not in (select max(b.rowidfrom stu b where a.no=b.no and a.name = b.name and a.sex = b.sex);                                          //这里max使用min也可以
或者用下面的语句
SQL>delete from stu a where rowid < (select max(b.rowidfrom stu b where a.no=b.no and a.name = b.name and a.sex = b.sex);       //这里如果把max换成min的话,前面的where子句中需要把"<"改为">"
 
跟上面的方法思路基本是一样的,不过使用了group by,减少了显性的比较条件,提高效率。
SQL>delete from stu where rowid not in (select max(rowidfrom stu t group by t.no, t.name, t.sex );
 
思考:若在stu表中唯一确定任意一行数据(1, 
‘ab‘,’男’),把sex字段更新为”女”,怎么做?
       
SQL>update stu set sex=’女’ where rowid=(select min(rowidfrom stu where no=1 and name=’ab’ and sex=’男’);

oracle中rownum和rowid的区别

标签:

原文地址:http://www.cnblogs.com/Alex-sgycs/p/5426165.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!