Oracle的伪列

伪列rownum,伪列就像表中的列一样,但是在表中并不存储。伪列只能查询,不能进行增删改操作。伪列的数据是由ORACLE进行维护和管理的,最常用的两个伪列:rownum和rowid。

在查询的结果集中,ROWNUM为结果集中每一行标识一个行号,第一行返回1,第二行返回2,以此类推。通过ROWNUM伪列可以限制查询结果集中返回的行数。

ROWNUM与ROWID不同,ROWID是插入记录时生成,ROWNUM是查询数据时生成。ROWID标识的是行的物理地址。ROWNUM标识的是查询结果中的行的次序。

1.ROWNUM:行号

ROWNUM(行号):是在查询操作时由ORACLE为每一行记录自动生成的一个编号。

每一次查询ROWNUM都会重新生成。(查询的结果中ORACLE给你增加的一个编号,根据结果来重新生成)

ROWNUM永远按照默认的顺序生成。(不受order by的影响)

ROWNUM只能使用 <、 <= ,不能使用 > 、>= 符号,原因是:Oracle是基于行的数据库,行号永远是从1开始,即必须有第一行,才有第二行。

1.1.ROWNUM的产生

ROWNUM是有数据库自己产生的,ROWNUM在查询的时候自动产生

SELECT ROWNUM,t.*
FROM emp t

1.2.ROWNUM的排序

对数据进行ORDER BY排序,不会影响到ROWNUM的顺序。ROWNUM永远按照默认的顺序生成。所谓的“默认的顺序”,是指系统按照记录插入时的顺序(其实是ROWID)。

需求:查询出所有员工信息,按部门号正序排列,并且显示默认的行号列信息。

SELECT ROWNUM,t.*
FROM emp t
ORDER BY deptno

ORDER BY 原理:将查询结果(此时行号已经有了,已经和每一行数据绑定了)进行排序。

ORDER BY 是查询语句出来的结果之后再排序的,ROWNUM是在查询出来结果的时候产生。所以ORDER BY不会影响到行号.

ORDER BY 排序,不会影响到ROWNUM的顺序。ROWNUM永远按照默认的顺序生成。所谓的“默认的顺序”,是指系统按照记录插入时的顺序(其实是ROWID)。

1.3.利用ROWNUM行号进行数据分页(重点)

我们知道,Mysql使用limit关键字可以实现分页,在Mysql中取n条数据可以写成:

select * from table limit m,n

其中m是指数据中的索引index,n是指从第m+1条开始,取n条。

select * from tablename limit 3,3 //即取出第4条至第6条,3条记录

但是在ORCALE中并没有limit关键字 那么在ORCALE中如何实现以上需求么?

需求:根据行号查询出第四条到第六条的员工信息。

错误写法:

SELECT ROWNUM,t. *
FROM emp t
WHERE ROWNUM >=4 AND ROWNUM<=6

以上写法之所以出错是因为ROWNUM只能使用 < 、<=,不能使用 > 、>=符号,原因是:Oracle是基于行的数据库,行号永远是从1开始,即必须有第一行,才有第二行。

SELECT ROWNUM,t.* 
FROM emp t 
WHERE ROWNUM<=6; //查询1-6条记录

使用子查询实现根据行号查询出第四条到第六条的员工信息:

SELECT ROWNUM,t2. 
FROM (
    SELECT ROWNUM r,t. *
    FROM emp t 
    WHERE ROWNUM <= 6
)  t2
WHERE t2.r >= 4

需求:要分页查询,每页3条记录,查询第二页

pageNum=2当前页码</br>
pageSize=3 最大记录数(即每页显示几条记录)

使用 mysql的分页查询语句,需要两个参数,起始索引和最大记录数

计算:</br>
起始索引:firstIndex=pageSize*(pageNum-1);</br>
最大记录数:maxCount=pageSize;

注意:</br>
1.sql中索引是从1开始的</br>
2.两个参数都是由当前页码和最大记录数计算出来的,所以使用时只定义页码和记录数即可</br>
3.第一页的参数为(0,3),不是说记录的起始索引从0开始,这只是一个参数,实际效果是
从第1条记录开始,记录数为3条,即查询1,2,3三条记录</br>
4.第二页的参数为(3,3),不是说记录的起始索引从3开始,这只是一个参数,实际效果是
从第4条记录开始,记录数为3条,即查询4,5,6三条记录,后面以此类推·····

Mysql语句:
select * from 表名 limit 起始索引,最大记录数

Oracle分析:</br>
//起始行号
firstRownum = pageSize(pageNum-1)+1</br>
//结束行号
endRownum = firstRownum+pageSize-1</br>
具体计算:
firstRownum=3
(2-1)+1=4;
endRownum=4+3-1=6;

写Oracle的分页,从子查询写起,也就是说从 <= 写起,或者说从endRownum写起:

SELECT ROWNUM ,t2.* 
FROM (
    SELECT ROWNUM r,t.* 
    FROM emp t 
    WHERE ROWNUM <= 6
) t2 WHERE t2.r >= 4

优化 --查询所有字段:

SELECT * 
FROM (
    SELECT ROWNUM r,t.* 
    FROM emp t 
    WHERE ROWNUM <=6
)

优化 -- 结果指定字段:

SELECT empno,ename,job 
FROM (
    SELECT ROWNUM r,t.* 
    FROM emp t 
    WHERE ROWNUM <=6
)  WHERE r >=4

需求:按照薪资的高低排序再分页

SELECT * 
FROM (
    SELECT ROWNUM r,t.* 
    FROM emp t 
    WHERE ROWNUM <=6 
    ORDER BY sal DESC
)

WHERE r >= 4 ;

以上代码分页成功,但定没有按照薪资的高低排序

改进:先排序薪资,再分页

SELECT * 
FROM (
  SELECT ROWNUM r,t.* 
  FROM (
    SELECT * 
    FROM emp 
    ORDER BY sal DESC
    ) t
  WHERE ROWNUM <=6 
  ORDER BY sal DESC
  )    
WHERE r >=4

Hibernate会自动将所有数据封装到实体对象(多余出来的行号那一列不会封装)

如果不需要额外的字段,则只需要指定特定的列名就可以了。

优化:子查询字段尽量少一些。数据量少。比如,表中有100个字段,但你就想显示5个,那么,你就子查询中直接指定5个就ok了。但使用orm框架的建议都查出来。

SELECT * FROM
  (
  SELECT ROWNUM r,t.* FROM 
         (SELECT ename,job,sal FROM emp ORDER BY sal DESC) t
   WHERE ROWNUM <=6 ORDER BY sal DESC
  )    
WHERE r >=4

通用查询代码

SELECT * FROM
  (
  SELECT ROWNUM r,t.* FROM 
         (SELECT ename,job,sal FROM emp ORDER BY sal DESC) t
   WHERE ROWNUM <=endRownum ORDER BY sal DESC
  )    
WHERE r >=firstRownum ;

【提示】:

如何记忆编写Oracle的分页?建议写的时候从里到外来写,即先写小于的条件的子查询(过滤掉rownum大于指定值的数据),再写大于的条件的查询(过滤掉rownum小于的值)。

Oracle的分页中如果需要排序显示,要先排序操作,再分页操作。(再嵌套一个子查询)

性能优化方面:建议在最里层的子查询中就直接指定字段或者其他的条件,减少数据的处理量。

1.4.ROWID

ROWID(记录编号):是表的伪列,是用来唯一标识表中的一条记录,并且间接给出了表行的物理位置,定位表行最快的方式。

主键:标识唯一的一条业务数据的标识。主键是给业务给用户用的。不是给数据库用的。

ROWID:标识唯一的一条数据的。主要是给数据库用的。类似UUID。

1.4.1. ROWID的查看

SELECT t.*,ROWID FROM emp t;

1.4.2. ROWID的产生

使用insert语句插入数据时,oracle会自动生成rowid 并将其值与表数据一起存放到表行中。

这与rownum有很大不同,rownum不是表中原本的数据,只是在查询的时候才生成的。rownum默认的排序就是根据rowid.

rowid 是插入数据时自动产生的,即是实际存在的,只是在查询时才显示出来,查询时不写rowid不显示但实际存在

1.4.3. ROWID的作用

1)快速删除重复的记录的方法

2)根据指定的列删除包含重复列值的记录(这种情况一般很少见,因为根据rowid删除的话很难判断删除以后保留下的行的其他列的值到底是什么)

【示例】需求:删除表中的重复数据,要求保留重复记录中最早插入的那条。(DBA面试题)

a.准备测试表和测试数据:

create table  test (id number, name varchar2(50))

b.插入测试数据

insert into test value(1,'xiaoming')
insert into test value(2,'xiaoming')
insert into test value(3,'xiaoming')
insert into test value(4,'zhongming')
insert into test value(5,'daming')
commit 

c.通过rowid,剔除重复xiaoming,保留最早插入的xiaoming

SELECT  t.*,ROWID 
FROM TEST t
WHERE ROWID > (
    SELECT MIN(ROWID) 
    FROM TEST
    );
DELETE FROM TEST t 
WHERE ROWID > (
    SELECT MIN(ROWID) 
    FROM TEST
    );

d.剔除重复数据

SELECT * FROM TEST WHERE ROWID NOT in(SELECT MIN(ROWID) FROM TEST GROUP BY NAME);
DELETE TEST WHERE ROWID NOT in(SELECT MIN(ROWID) FROM TEST GROUP BY NAME);

注意:删除重复记录一定要小心,万一你的条件有问题,就会删错数据.建议删除之前,可以先用查询查一下,看是否是目标数据。

数据一旦删除恢复比较麻烦,但可以恢复,采用日志回滚。一般不要轻易用。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,634评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,951评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,427评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,770评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,835评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,799评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,768评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,544评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,979评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,271评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,427评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,121评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,756评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,375评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,579评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,410评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,315评论 2 352

推荐阅读更多精彩内容

  • 转 # https://www.cnblogs.com/easypass/archive/2010/12/ 08/...
    吕品㗊阅读 9,718评论 0 44
  • ORA-00001: 违反唯一约束条件 (.) 错误说明:当在唯一索引所对应的列上键入重复值时,会触发此异常。 O...
    我想起个好名字阅读 5,300评论 0 9
  • 大家都知道,榜样的力量是无穷的。小时候,我们学习了英雄的故事,热血沸腾,希望自己也能像英雄一样,堵机枪、炸碉堡,为...
    劉清阅读 422评论 0 5
  • 原文链接:TCP的拥塞控制 1.引言 计算机网络中的带宽、交换结点中的缓存和处理机等,都是网络的资源。在某段时间,...
    环球探测阅读 890评论 0 1
  • 先聚焦做完手头一件事,这样做事情效率高。这是朋友R教我的重要小事。 一次我们俩一起改稿子,开始的时间差不多,稿子量...
    泽阳9阅读 302评论 1 2