轉自:http://blog.csdn.net/happyqiuqiang/article/details/52230051
一、簡單介紹一下ROWNUM是什么,可以用來干什么。
答:ROWNUM是一個序列,會根據sql語句自動給你加上一列排好順序的序號列。For example!
你有一張全班同學的各科目成績表。
1、然后你想給這張表按語文成績加上排名。你會怎么做?
SELECT G.ID, G.NAME, G.CHINESE, ROWNUM AS CHINESE_SORT, G.MATH, G.ENGLISH
FROM (SELECT * FROM GRADE ORDER BY CHINESE) G
如果對所有科目成績加上排名序號列呢?
提示一下這回要用到left join了,left join會在下一篇文章中講解。先看下面sql代碼:
SELECT *
FROM (SELECT T.NAME,
T.CHINESE,
T1.CHINESE_SORT AS CHINESE_SORT,
T.MATH,
T2.MATH_SORT AS MATH_SORT,
T.ENGLISH,
T3.ENGLISH_SORT AS ENGLISH_SORT
FROM GRADE T
LEFT JOIN (SELECT G1.NAME, G1.CHINESE, ROWNUM CHINESE_SORT
FROM (SELECT g.NAME, g.CHINESE
FROM GRADE g
ORDER BY g.CHINESE DESC) G1) T1
ON T1.NAME = T.NAME
LEFT JOIN (SELECT G2.NAME, G2.MATH, ROWNUM MATH_SORT
FROM (SELECT g.NAME, g.MATH
FROM GRADE g
GROUP BY g.NAME, g.MATH
ORDER BY g.MATH DESC) G2) T2
ON T2.NAME = T.NAME
LEFT JOIN (SELECT G3.NAME, G3.ENGLISH, ROWNUM ENGLISH_SORT
FROM (SELECT g.NAME, g.ENGLISH
FROM GRADE g
GROUP BY g.NAME, g.ENGLISH
ORDER BY g.ENGLISH DESC) G3) T3
ON T3.NAME = T.NAME) MyGrade
ORDER BY MyGrade.CHINESE_SORT;
執行代碼后結果如下圖所示
二、上面的內容主要講解了ROWNUM的排序,是rownum最基本最直接的用法。不過rownum最常見的用法是用來做分頁。
還是那張成績變:
1、只顯示前語文成績前十名的學生記錄
select g.* from grade g where rownum < 10 order by chinese;
很簡單有沒有。
2、想知道語文成績第10名以后的學生記錄:
select g.* from grade g where rownum > 10 order by chinese;
是這樣嗎?執行一下,並沒有結果。
原因:文章開頭說ROWNUM是一個序列,會根據sql語句自動給你加上一列排好順序的序號列。
rownum總是為滿足條件的記錄從1開始設序號,所以rownum總是從1開始的。這理解起來並沒有問題哈。當從數據庫中找到語文成績第一名的記錄時,設序號為1,該記錄不滿足rownum>10。所以拋棄該記錄,接着從數據庫中找到語文成績第二名的記錄,又設序號為1,該記錄依然不滿足rownum>10,依次類推。所以窮盡整張表拋棄了所有記錄。
正確的sql應該這樣寫:
select MyGrade.*
from (select G.*, rownum rn
from (select g.* from grade g order by chinese) G ) MyGrade
where MyGrade.rn >= 10;
先select所有記錄並按語文成績排好序,外套一個select加上序號列。這就為所有記錄固定好了排序的順序。再外套一個select取出從序號>=10 的所有記錄;
3、獲取第語文成績有潛力提升到高分階段的批次記錄,比如第6名到第10名的記錄:
select MyGrade.*
from (select G.*, rownum rn
from (select g.* from grade g order by chinese) G
where rownum <= 10) MyGrade
where MyGrade.rn >= 6;
當然,下面這段sql也可以實現同樣的效果:
select MyGrade.*
from (select G.*, rownum rn
from (select g.* from grade g order by chinese) G
where rownum <= 10) MyGrade
where MyGrade.rn >= 6 and MyGrade.rn <= 10;
不過當數據量很大時,這段代碼性能就次了好多,因為它要先遍歷所有記錄,然后根據序號分頁。而對於之前的代碼,由於CBO優化模式下,Oracle可以將外層的查詢條件推到內層查詢中,以提高內層查詢的執行效率,所以只是遍歷了rownum小於10的記錄,就停止了內層查詢。所以推薦使用第一種分頁方法。
好了,rownum先講到這里。如果有需要會在之后的文章中補充。下一篇文章講解inner join、left join和right join的區別和使用。