Oracle - ROWNUM、BETWEEN...AND... 分頁查詢


測試表 EMP

SELECT * FROM EMP;

 

ROWNUM(順便對比下 ROWID)

ROWID 和 ROWNUM 都是偽列,但含義完全不同。

  • ROWID 是物理地址,用於定位 Oracle 中具體數據的物理存儲位置,用於定位數據表中某條數據的位置,是唯一的、也不會改變。
  • ROWNUM 則是 SQL 的輸出結果排序。表示查詢某條記錄在整個結果集中的位置, 同一條記錄,查詢條件不同,對應的 ROWNUM 是不同的,而 ROWID 是不會變的。
  • ROWID 是相對不變的,ROWNUM 會變化,尤其是使用 ORDER BY 的時候。

ROWNUM 對性能的影響:

  • ROWNUM 可以避免 Oracle 在磁盤上進行排序。ROWNUM 無法避免全表掃描的發生,但是它可以避免對整個表數據的排序操作,在指定了 ROWNUM 后,排序操作在內存中可以輕松完成。

 

WHERE ROWNUM >= 1、ROWNUM >= 0、ROWNUM > 0,查詢結果一致

SELECT * FROM EMP WHERE ROWNUM >= 1;
SELECT * FROM EMP WHERE ROWNUM >= 0;
SELECT * FROM EMP WHERE ROWNUM > 0;

 

WHERE ROWNUM = 1,查詢結果為一條記錄,沒毛病

SELECT * FROM EMP WHERE ROWNUM = 1;

 

WHERE ROWNUM > 1 或者 ROWNUM = 一個比 1 大的數(ROWNUM = 2),查詢結果為空

SELECT * FROM EMP WHERE ROWNUM > 1;-- 查詢的不是第 2~14 條記錄,查詢結果為空! 
SELECT * FROM EMP WHERE ROWNUM = 2;-- 以為查詢的結果是第 2 條記錄嗎?不好意思,查詢結果為空!
SELECT * FROM EMP WHERE ROWNUM >= 10;-- 是不是以為查詢的結果是表中第 10~14 條記錄,但是明顯不是,查詢結果為空!

 

上面幾組 SQL,執行結果,解析如下:

  • ROWNUM > 0、ROWNUM >= 0、ROWNUM >=1,如果 WHERE ROWNUM 條件如前面三種的話,查詢的結果為 ROWNUM 從 1 開始,到最后一條記錄(即全部記錄)
  • 原因是:ROWNUM 作為 Oracle 表記錄的偽列,從 1 開始,即ROWNUM(1、2、3、4、5...、14),ROWNUM > 1,對於第一行來說,並不是真值,因為 ROWNUM 從 1 開始,ROWNUM > 1,真值為 false,而后表記錄中原 ROWNUM 為 2 的記錄補上,新的 ROWNUM 為 1~13,同理,ROWNUM > 1 真值還是 false,然后初始記錄 ROWNUM = 3 的記錄補上,新的 ROWNUM 為 1~12,以此類推,ROWNUM > 1 結果真值永遠為 false,所以,查詢的結果集總為空!
  • 結果可知,SELECT * FROM EMP WHERE ROWNUM [condition],condition 條件永遠不要使用 ROWNUM > ? 或者 ROWNUM = n(n!=1),因為這樣意義不大。

 

WHERE ROWNUM < 或 <= n(n 大於 1)

SELECT * FROM EMP WHERE ROWNUM <= 10;-- 前 10 條記錄

解析:

  • SELECT * FROM EMP WHERE ROWNUM <= 10,結果和預期一致。
  • ROWNUM <= 10,第一條記錄 ROWNUM 為 1,條件 ROWNUM <=10 為 true,然后 ROWNUM 增長為 2,條件仍為 true,直到 ROWNUM 增長為 10,條件仍為 true,ROWNUM 增長為 11,ROWNUM <= 10 條件為 false,此時原記錄中 ROWNUM = 12 的記錄補上,ROWNUM 仍為 11,ROWNUM <= 10 條件恆為 false。則查詢結果集是:ROWNUM 從 1 到 10 的記錄

 

WHERE ROWNUM != n(n 大於 1)

SELECT * FROM EMP WHERE ROWNUM != 10;

分析過程,和上面類似。ROWNUM 從 1~9,ROWNUM != 10 結果都為 ture,當 ROWNUM 增長到 10,ROWNUM != 10,判斷條件為 false,所以只查詢出第 1~9 條記錄。

 

BETWEEN...AND...

SELECT * FROM EMP WHERE ROWNUM BETWEEN 1 AND 10;

 

BETWEEN 2 AND n,從 2 或者 任何大於 1  開始,到 n

SELECT * FROM EMP WHERE ROWNUM BETWEEN 2 AND 10;-- 查詢為空!

 分析:

  • BETWEEN START AND END,ROWNUM 總是從 1 開始,所以 START 去和數據文件或者緩沖區中讀取讀取第一條記錄(ROWNUM 為 1),不符合,所以 ROWNUM = 1 這條記錄從臨時表中刪除,下一條記錄補上,作為新的記錄 ROWNUM  =1 繼續比較 ,真值仍為 false,以此類推,導致查詢結果集為空!
  • 所以,想直接通過 WHERE ROWNUM BETWEEN START AND END 來進行分頁查詢,不奏效。為此就要借助子查詢,將 ROWNUM 偽列,作為字段,在子查詢中查詢出來,然后做分頁查詢。

 

Oracle 利用 ROWNUM 做分頁查詢:

SELECT M.*
  FROM (SELECT ROWNUM AS RN, T.* FROM EMP T WHERE ROWNUM <= 8) M
 WHERE RN >= 3;
SELECT M.*
  FROM (SELECT ROWNUM AS RN, T.* FROM EMP T) M
 WHERE RN BETWEEN 3 AND 8;

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM