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閱讀 227,702評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,143評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,553評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,620評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,416評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,940評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,024評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,170評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,709評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,597評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,291評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,029評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,407評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,663評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,403評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,746評論 2 370

推薦閱讀更多精彩內容

  • 轉 # https://www.cnblogs.com/easypass/archive/2010/12/ 08/...
    呂品?閱讀 9,753評論 0 44
  • ORA-00001: 違反唯一約束條件 (.) 錯誤說明:當在唯一索引所對應的列上鍵入重復值時,會觸發此異常。 O...
    我想起個好名字閱讀 5,375評論 0 9
  • 大家都知道,榜樣的力量是無窮的。小時候,我們學習了英雄的故事,熱血沸騰,希望自己也能像英雄一樣,堵機槍、炸碉堡,為...
    劉清閱讀 435評論 0 5
  • 原文鏈接:TCP的擁塞控制 1.引言 計算機網絡中的帶寬、交換結點中的緩存和處理機等,都是網絡的資源。在某段時間,...
    環球探測閱讀 903評論 0 1
  • 先聚焦做完手頭一件事,這樣做事情效率高。這是朋友R教我的重要小事。 一次我們倆一起改稿子,開始的時間差不多,稿子量...
    澤陽9閱讀 314評論 1 2