ROWNUM 是在 資料取出後、排序前 分配的偽欄位。直接寫 WHERE ROWNUM BETWEEN 11 AND 20 永遠回傳 0 筆,因為第一筆 ROWNUM=1 不符合 >=11,後續筆數永遠無法成長到 11。
SELECT *
FROM (
SELECT ROWNUM rn, a.*
FROM (
SELECT * FROM tablename ORDER BY showorder
) a
WHERE ROWNUM <= 20
)
WHERE rn >= 11;
| 層級 | 作用 | 關鍵點 |
|---|---|---|
| 最內層 | SELECT * FROM tablename ORDER BY showorder | 先完成業務排序 |
| 中間層 | SELECT ROWNUM rn, a.* ... WHERE ROWNUM <= 20 | 對已排序結果打標號,並截取前 20 筆 |
| 最外層 | WHERE rn >= 11 | 過濾出第 11-20 筆(rn 為實際欄位可正常比較) |
測試千筆資料表,PL/SQL 執行耗時 0.078 秒,等同於僅查前 10 筆的速度。Oracle 能在中間層 ROWNUM <= 20 觸發 COUNT STOPKEY 最佳化,提早終止掃描。
SELECT * FROM tablename
ORDER BY showorder
OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY;
標準 SQL 語法,可讀性高,執行計畫同等最佳化。
-- 錯誤 1:直接 BETWEEN
SELECT * FROM tablename WHERE ROWNUM BETWEEN 11 AND 20 ORDER BY showorder; -- 0 rows
-- 錯誤 2:排序在外層
SELECT * FROM (SELECT * FROM tablename WHERE ROWNUM <= 20) ORDER BY showorder; -- 排序錯亂
-- 錯誤 3:未在中間層限制 ROWNUM
SELECT * FROM (SELECT ROWNUM rn, a.* FROM (SELECT * FROM tablename ORDER BY showorder) a) WHERE rn BETWEEN 11 AND 20; -- 全表掃描