TOP-N查詢(TOP-N分析):就是獲取某一數據集合中的前N條記錄,實際應用中經常用到。
Oracle中不支持SELECT TOP語句(MySQL中也沒用此語句),需要借助ROWNUM偽列來實現TOP-N查詢。
ROWNUM偽列:是Oracle數據庫對查詢結果自動添加的一個偽列,編號從1開始。ROWNUM在物理上(查詢目標表中)並不存在,是每一次查詢過程中動態生成的,所以稱為“偽列”。因此,不允許以任何查詢基表的名稱做為前綴,連接查詢中涉及多個物理表,但也只動態生成一個偽列。
1、非排序查詢TOP-N分析
例題:返回員工信息表前5條記錄
2、排序查詢TOP-N分析
SELECT語句的執行順序:先WHERE,后ORDER BY
例題:按照工資降序排序,查詢工資最高的前5名員工的信息。
錯誤答案:
正確答案:
內層排序,外層設定范圍(WHERE只能設定從1開始的范圍)。如rownum<=5,不能設定這樣的范圍,如rownum<=13 and rownum>=18)
子查詢和主查詢分別會產生各自的ROWNUM偽列,而此處用的是主查詢自己的偽列。為了分析,請看下面的語句:
“原始行號”rn是子查詢結果排序之前的行號(子查詢執行力WHERE子句,但沒有執行ORDER BY子句時的行號),結果如下:
3、分頁查詢(應用極廣)
分頁顯示的目的是控制輸出結果集大小,將結果盡快返回。
例題:按照工資逆序、分頁顯示員工信息,每頁顯示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不能被識別)