oracle數據類型----rownum

rownum是一個比較容易混淆的概念,要正確的理解rownum僞列,首先我們要明白它的工作原理.

   rownum工作機制:
   1 Oracle executes your query.

   2 Oracle fetches the first row and calls it row number 1.

   3 Have we gotten past row number meets the criteria? If no, then Oracle discards the row, If yes, then Oracle return the row.

   4 Oracle fetches the next row and advances the row number (to 2, and then to 3, and then to 4, and so forth).

   5 Go to step 3.
   正確的理解rownum工作機制很重要,以下做一些說明:
   1 oracle首先執行查詢,產生結果集.
   2 oracle的rownum值的生成是基於這個結果集的,在產生結果集之後對rownum僞列賦值
     需要注意的是:
      a. rownum並不是在查詢時就對僞列進行賦值了,而是在查詢完成之後在數據排序之前賦值的.
      b. rownum是在oracle取數據的時候就進行賦值了,也就是在數據排序之前賦值的.
      c. rownum賦值是始終是從1開始的,結果集中的rownum的值是從1~n的連續的自然數.這個可以視爲oracle對rownum僞列的一個約束
       d. rownum僞列不屬於任何基表,不能使用基本來引用rownum僞列
   3 oracle取得的記錄是否滿足where子句條件,如果滿足則保留結果集中的這條記錄,如果不滿足就移除結果集中的這條記錄,因爲rownum要滿足僞列的約束,即rownum僞列要滿足從1~n連續的自然數約束,所以移除記錄後對後續的rownum賦值時,就按1~n連續自然數的規則來賦值,即下一條記錄的rownum會被賦予上一條不符合where條件記錄的rownum值
    4 oracle繼續爲下一條記錄的rownum僞列賦值
    5 返回到第三步

從以上的說明中我們可以解釋以下sql運行的"怪異"結果.
   e.g.
       create table STUDENT
      (
         ID                NUMBER(12) not null,
         NAME            VARCHAR2(20) not null,
         AGE                NUMBER(3) not null,
         GMT_CREATE      TIMESTAMP(6) not null,
      )
   往該表插入20條數據....(省略,自已想象....)
   1.select * from STUDENT where rownum > 5
     這條sql返回的結果集是空集.原因是oracle執行查詢select * from STUDENT返加結果集之後,對rownum僞列進行賦值.當取得結果集的第一條記錄時,給僞列rownum賦值爲1,而1並不滿足where子句中rownum>5的條件,因此,移除這條記錄;然後oracle再取得下一條記錄,因爲rownum要滿足1~n連續自然數的約束,所以oracle令該rownum=1,而這條記錄也不滿足rownum>5的條件,依次類推,所有記錄都不滿足條件.因此查詢的是空值.
   2.select * from STUDENT where rownum != 5     這條sql返回的結果集包含4條數據.原因是當oracle爲第五條記錄的rownum賦值時,該rownum==5,不滿足rownum!=5的條件,因此移除這條記錄,繼續爲下一條記錄的rownum賦值,而rownum必須滿足1~n連續自然數的約束,因此這條記錄的rownum其實也是5,仍然不滿足條件,依次類推,返回的結果集只包含前4條記錄
    3.select t.rownum from STUDENT t
     這條sql將返回錯誤,因爲rownum是針對結果集賦值的,它是在表查詢之後產生的,並不屬於表結構的一部分,因此t.rownum是個錯誤的寫法。而t.rowid是沒有問題的.
   4.select rownum,* from STUDENT t
      這條sql返回錯誤,因爲rownum是針對結果集的,而*是針對結果集的所有列還是表結構STUDENT的所有列呢,這裏需要指明*所屬的表結構或者視圖.select rownum,t.* from STUDENT t是一種正確的寫法
    5.select rownum,t.* from STUDENT t order by t.AGE desc
      這條sql返回的結果集是按照記錄的年齡進行排序的,由於rownum的賦值是在對結果集排序之前完成的,因此把結果集按年齡排序後的記錄的rownum可能就不是按自然順序1~n進行排序的.select rownum,t.* from STUDENT t結果集中rownum是按自然順序1~n排列的.
    6.select rownum,t.* from(select * from STUDENT order by AGE)t
       這條sql返回的結果集的rownum是按自然順序1~n排列的.
    7.select * from
            (
               select t.*, rownum rn
                 from (select * from STUDENT) t
                 where rownum <= 10
             )
            where rn >= 2

       這條sql是標準的oracle分頁查詢sql,還有一些非標準的就是不列出來了,呵呵.由於每個視圖a都包含它自已的rownum僞列(始終從1開始賦值),因此要使用另一個視圖b的rownum僞列就需要爲視圖b的rownum僞列定義一個別名.最內層的查詢由於可能要使用order by子句,因此最好不要把rownum放到最內層的查詢中.

 

出處:http://wagtto.javaeye.com/blog/465432

發佈了15 篇原創文章 · 獲贊 4 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章