TOP-N查詢(TOP-N分析):就是獲取某一數據集合中的前N條記錄,實際應用中常常用到。數據庫
Oracle中不支持SELECT TOP語句(MySQL中也沒用此語句),須要藉助ROWNUM僞列來實現TOP-N查詢。優化
ROWNUM僞列:是Oracle數據庫對查詢結果自動添加的一個僞列,編號從1開始。ROWNUM在物理上(查詢目標表中)並不存在,是每一次查詢過程當中動態生成的,因此稱爲「僞列」。所以,不容許以任何查詢基表的名稱作爲前綴,鏈接查詢中涉及多個物理表,但也只動態生成一個僞列。spa
例題:返回員工信息表前5條記錄3d
SELECT語句的執行順序:先WHERE,後ORDER BYblog
例題:按照工資降序排序,查詢工資最高的前5名員工的信息。排序
錯誤答案:get
正確答案:select
內層排序,外層設定範圍(WHERE只能設定從1開始的範圍)。如rownum<=5,不能設定這樣的範圍,如rownum<=13 and rownum>=18)分頁
子查詢和主查詢分別會產生各自的ROWNUM僞列,而此處用的是主查詢本身的僞列。爲了分析,請看下面的語句:im
「原始行號」rn是子查詢結果排序以前的行號(子查詢執行力WHERE子句,但沒有執行ORDER BY子句時的行號),結果以下:
分頁顯示的目的是控制輸出結果集大小,將結果儘快返回。
例題:按照工資逆序、分頁顯示員工信息,每頁顯示6行記錄。假定當前要顯示第3頁(即13~18行),應如何獲取該頁數據?
錯誤答案:該代碼不會返回任何查詢結果。
分析:ROWNUM自動編號從1開始。主查詢執行時,取出子查詢結果集中的第一條記錄,並將其ROWNUM賦值爲1,不符合WHERE限定的條件(13~18),因而這條記錄被過濾掉。取出子查詢結果集中的第二條記錄,並將其ROWNUM賦值爲1(由於前面沒有找到過符合WHERE條件的記錄),依次類推,永遠也得不到符合條件的記錄。(咱們永遠也沒法繞過第一個,而直接去吃到第二個饅頭)
正確答案:加一層嵌套查詢,對子查詢中的ROWNUM的值進行「固化」處理(使得rn是物理上存在的),在主查詢中便可對其進行任意範圍的取值判斷。
最內層排序(ORDER BY),中間層「固化」ROWNUM,最外層設定範圍(WHERE中能夠設定任意範圍)。
select * from (select rownum r,t1.* from (select * from emp order by sal desc) t1) t2 where t2.r between 6 and 10;
優化後:
正確寫法:select * from (select rownum r,t1.* from (select * from emp order by sal desc) t1 where rownum<=10) t2 where t2.r>=6; (減小了t1表返回的數據,有優化做用)
錯誤寫法:select * from (select rownum r,t1.* from (select * from emp order by sal desc) t1 where t1.rownum<=10) t2 where t2.r>=6;(rownum是僞列,前面不能加表名修飾)
錯誤寫法:select * from (select rownum r,t1.* from (select * from emp order by sal desc) t1 where r<=10) t2 where t2.r>=6;(r在where中,而where是最早執行的,以前並無執行rownum r,因此致使where中的r不能被識別)