ROWNUM 在資料列被**擷取/過濾時**動態賦值。直接寫 WHERE ROWNUM BETWEEN 30 AND 49 永遠回傳空集合,因第一列 ROWNUM=1 不滿足 ≥30 被丟棄,後續列遞補為 1 同理被丟棄。
-- 步驟 1:先取前 N 列
SELECT * FROM all_objects WHERE ROWNUM <= 49;
-- 步驟 2:外層過濾起始位置
SELECT * FROM (
SELECT ROWNUM rn, a.* FROM all_objects a WHERE ROWNUM <= 49
) WHERE rn >= 30;
SELECT * FROM (
SELECT ROWNUM rn, a.* FROM all_objects a WHERE ROWNUM <= :max_row
) WHERE rn >= :min_row;
相同 SQL 文本、不同綁定值可共享游標,消除重複解析開銷。
CREATE OR REPLACE PROCEDURE search_page (
p_min IN NUMBER,
p_max IN NUMBER,
p_rc OUT SYS_REFCURSOR
) IS
BEGIN
OPEN p_rc FOR
SELECT * FROM (
SELECT ROWNUM rn, a.* FROM all_objects a WHERE ROWNUM <= p_max
) WHERE rn >= p_min;
END search_page;
/
應用層僅需呼叫存儲過程,直接獲取所需頁面資料集,無需在中介層過濾。
ROWNUM 在 ORDER BY **之後** 計算,因此排序會改變分頁結果順序。基於規則的優化器(RBO)會利用 ROWNUM 短路查詢,滿足條件即停止掃描。
SELECT * FROM all_objects
ORDER BY object_id
OFFSET 29 ROWS FETCH NEXT 20 ROWS ONLY;
Oracle 12c 起支援 ANSI 標準分頁語法,碼更清晰、優化器支援更佳,建議新專案優先採用。
| 方案 | 適用版本 | 優點 | 缺點 |
|---|---|---|---|
| ROWNUM 雙層嵌套 | 8i+ | 相容性最廣 | SQL 複雜、需小心綁定變數 |
| ROWNUM + 存儲過程 | 8i+ | 封裝邏輯、回傳游標 | 需維護 PL/SQL |
| OFFSET/FETCH | 12c+ | 標準語法、可讀性高 | 舊版本不支援 |
Oracle 分頁核心在於「先限制上限、再過濾下限」。生產環境務必使用綁定變數並封裝為存儲過程,12c 以上版本請直接採用 OFFSET/FETCH 簡化開發。