測試表 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;