ROWNUM 是 Oracle 為結果集動態分配的偽列,分配時機在 WHERE 條件過濾之後、ORDER BY 排序之前。這一機制導致直接在外層使用 ROWNUM 配合 ORDER BY 會產生錯誤結果。本文深度解析 ROWNUM 運作原理、分頁正確寫法、> / >= / BETWEEN 失效原因、效能優化特性。
執行順序: 1. FROM / WHERE 子句執行,產生候選行集 2. 對候選行集依次分配 ROWNUM (從 1 開始遞增) 3. SELECT 列表投影 4. GROUP BY / HAVING 5. ORDER BY 排序 (此時 ROWNUM 已固定)
關鍵推論:
ROWNUM永遠反映「未排序結果集中的相對位置」。若先ORDER BY再取ROWNUM,必須用子查詢先排序,外層再套用ROWNUM。
-- 錯誤寫法:先取前 20 行,再排序 → 取得的是前 20 行未排序子集的排序,非全表排序前 20
SELECT * FROM (
SELECT r.*, ROWNUM RN FROM (SELECT * FROM tbrole) r WHERE ROWNUM <= 20
) WHERE RN >= 1 ORDER BY CREATE_TIME ASC;
-- 正確寫法:內層先排序,中層套 ROWNUM,外層篩選 RN 範圍
SELECT * FROM (
SELECT r.*, ROWNUM RN FROM (
SELECT * FROM tbrole ORDER BY CREATE_TIME ASC
) r WHERE ROWNUM <= 20
) WHERE RN >= 1; -- 第 1 頁 (1-20)
-- 第 2 頁 (21-40)
SELECT * FROM (
SELECT r.*, ROWNUM RN FROM (
SELECT * FROM tbrole ORDER BY CREATE_TIME ASC
) r WHERE ROWNUM <= 40
) WHERE RN > 20;
| 條件 | 結果 | 原因 |
|---|---|---|
ROWNUM = 1 | 正常 (首行) | 第一行滿足,分配 1,通過 |
ROWNUM <= 10 | 正常 (前 10 行) | 前 10 行依次分配 1~10,均通過 |
ROWNUM > 10 | 永遠無行 | 第一行分配 1 不滿足 >10 被過濾;第二行因第一行被過濾,仍分配 1,永無機會達到 >10 |
ROWNUM >= 10 | 永遠無行 | 同理 |
ROWNUM BETWEEN 5 AND 10 | 永遠無行 | 同理 |