ROWNUM 是 Oracle 查詢結果集的行號偽欄位,而非儲存屬性。其「先產生結果集、再分配行號」的特性導致 >、=、BETWEEN 等條件失效。本文系統解析 ROWNUM 行為邏輯、分頁查詢正確寫法、子查詢別名要求、ROWID 差異與實戰避坑清單。
FROM → WHERE → SELECT → ORDER BY → ROWNUM 分配| 錯誤寫法 | 預期結果 | 實際結果 | 原因 |
|---|---|---|---|
WHERE rownum > 10 | 第 11 行之後 | 無資料 | 第一行 rownum=1 不滿足 >10 被過濾,第二行變 rownum=1 仍不滿足,循環導致全無 |
WHERE rownum = 5 | 第 5 行 | 無資料 | 同理,永無 rownum=5 的機會 |
WHERE rownum BETWEEN 5 AND 10 | 第 5-10 行 | 無資料 | 首行 rownum=1 不在範圍,後續永遠從 1 開始 |
WHERE rownum != 10 | 除第 10 行外所有 | 前 9 行 | 第 10 行被過濾後,第 11 行變 rownum=10 又被過濾,以此類推 |
| 特性 | ROWNUM | ROWID |
|---|---|---|
| 本質 | 查詢結果集行號 (邏輯、暫時) | 資料行物理地址 (物理、永久) |
| 生命週期 | 單次查詢內 | 行不移動/不刪除則永久不變 |
| 唯一性 | 單查詢內唯一 | 資料庫全域唯一 |
| 可作為條件 | 受分配順序限制 | 隨時可用,WHERE rowid = 'AAAR...' 直接定位 |
| 分頁適用性 | 需子查詢包裝 | 不適用 (無序) |
SELECT * FROM large_table
WHERE status = 'ACTIVE'
ORDER BY created_dt DESC
OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY;
rownum > N、rownum = N、rownum BETWEENrownum 必須起別名,否則外層引用會產生新 rownumOFFSET/FETCH,舊版用標準三層寫法t.rownum 錯誤),ROWID 可以 (t.rowid)-- 取前 10 筆最高薪員工 (索引範圍掃描下推)
SELECT * FROM (
SELECT * FROM emp ORDER BY sal DESC
)
WHERE rownum <= 10;
Oracle 會將 rownum <= 10 推送到索引範圍掃描層,僅讀取 10 個索引條目,極高效率。
理解 ROWNUM「先過濾、後編號」的本質,是寫出正確高效 Oracle 分頁查詢的關鍵。