标签:
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 distinct* from 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; --测试 SQL> select * from student; ID NAME ------ ------------------------ 200001 张一 200002 王二 200003 李三 200004 赵四 ⑴ rownum 对于等于某值的查询条件 如果希望找到学生表中第一条学生的信息,可以使用rownum=1作为条件。但是想找到学生表中第二条学生的信息,使用rownum=2结果查不到数据。因为rownum都是从1开始,但是1以上的自然数在rownum做等于判断时认为都是false条件,所以无法查到rownum = n(n>1的自然数)。 SQL> select rownum,id,name from student where rownum=1; ROWNUM ID NAME ---------- ------ --------------------------------------------------- 1 200001 张一 SQL> select rownum,id,name from student where rownum =2; 未选定行 ⑵ rownum对于大于某值的查询条件 如果想找到从第二行记录以后的记录,当使用rownum>2是查不出记录的,原因是由于rownum是一个总是从1开始的伪列,Oracle 认为rownum> n(n>1的自然数)这种条件依旧不成立,所以查不到记录。 SQL> select 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 赵四 SQL> select * from(select rownum,id,name from student)where rownum>2; 未选定行 ⑶ rownum对于小于某值的查询条件 如果想找到第三条记录以前的记录,当使用rownum<3是能得到两条记录的。显然rownum对于rownum1的自然数)的条件认为是成立的,所以可以找到记录。 SQL> select 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的记录行。但是这样的操作会在大数据集中影响速度。 SQL> select * 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行数据就必须注意了。 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标出正确序号(由小到大)。order by name 如果name是主键或有索引 ,查询出来的rownum完全按照1,2,3.....的次序。 SQL> alter table student add constraint pk_stu primary key(name); SQL> select 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 SQL> create table stu(no number,name varchar2(10),sex char(2)); --添加测试记录 SQL> insert into stu values(1, ‘ab‘,’男’); SQL> insert into stu values(1, ‘bb‘,’女’); SQL> insert into stu values(1, ‘ab‘,’男’); SQL> insert into stu values(1, ‘ab‘,’男’); SQL>commit; 删除重复记录方法很多,列出两种。 ⑴ 通过创建临时表 可以把数据先导入到一个临时表中,然后删除原表的数据,再把数据导回原表,SQL语句如下: SQL>create table stu_tmp as select distinct* from 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.rowid) from 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.rowid) from 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(rowid) from stu t group by t.no, t.name, t.sex ); 思考:若在stu表中唯一确定任意一行数据(1, ‘ab‘,’男’),把sex字段更新为”女”,怎么做? SQL>update stu set sex=’女’ where rowid=(select min(rowid) from stu where no=1 and name=’ab’ and sex=’男’); |
标签:
原文地址:http://www.cnblogs.com/Alex-sgycs/p/5426165.html