首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> Oracle 資料庫 >> Oracle 資料庫基礎

Oracle 分頁查詢完全指南:ROWNUM、ROW_NUMBER() 與 Top-N 寫法詳解

     編輯:Oracle 資料庫基礎

Oracle 無 LIMIT/OFFSET(12c 前),分頁查詢依賴 ROWNUM 偽欄或 12c+ FETCH FIRST。本文系統整理 ROWNUM 陷阱、ROW_NUMBER() 分析函數、分組 Top-N、以及「先排序再取」vs「先取再排」的效能與正確性權衡。

基礎:取前 10 筆

SELECT * FROM test WHERE ROWNUM <= 10;

ROWNUM 從 1 開始遞增,**只能用 <= 或 <**,不能用 >=。

分頁:取第 11~20 筆(經典子查詢法)

SELECT * FROM (
  SELECT a.*, ROWNUM rn FROM test a
) WHERE rn BETWEEN 11 AND 20;

內層賦予 ROWNUM 別名 rn,外層才能用 >= 篩選。

「先排序再取」vs「先取再排」—— 關鍵陷阱

寫法 A:正確(子查詢先排序)

SELECT * FROM (
  SELECT * FROM torderdetail ORDER BY order_date DESC
) WHERE ROWNUM <= 10;

全表掃描 → 排序 → 取前 10。結果正確,但大表排序耗資源。

寫法 B:高風險(WHERE ROWNUM 先取,外層 ORDER BY)

SELECT * FROM torderdetail
WHERE ROWNUM <= 10
ORDER BY order_date DESC;

執行順序:**先取 10 筆(隨機/物理順序)→ 再排序**。

  • 若 ORDER BY 欄位是 **PK/Unique Index**,Oracle 可能優化為「Index Full Scan Desc + Stopkey」,**先排序再取**,結果正確且極快。
  • 若 ORDER BY 非 PK,**先取再排**,結果**錯誤**(非最新 10 筆)。

⚠️ 生產環境**嚴禁**使用寫法 B,除非確定排序欄位有唯一索引且經驗證執行計畫出現 COUNT STOPKEY。

12c+ 簡潔語法:FETCH FIRST

SELECT * FROM torderdetail
ORDER BY order_date DESC
FETCH FIRST 10 ROWS ONLY;

-- 分頁:OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY

內部自動轉換為最佳執行計畫,建議 12c+ 專案直接使用。

ROW_NUMBER() 分析函數(9i+)

SELECT * FROM (
  SELECT a.*, ROW_NUMBER() OVER (ORDER BY order_date DESC) rn
  FROM torderdetail a
) WHERE rn <= 10;

與 ROWNUM 子查詢效能相當,語意更清晰。

進階:分組 Top-N(每組取前 N)

ROWNUM 無法實現**,必須用 ROW_NUMBER() + PARTITION BY。

-- 每天取最新 10 筆訂單
SELECT * FROM (
  SELECT a.*,
         ROW_NUMBER() OVER (PARTITION BY TRUNC(order_date) ORDER BY order_date DESC) rn
  FROM torderdetail a
) WHERE rn <= 10;

ROWNUM 特殊用法:產生日期序列

-- 當月每一天
SELECT TRUNC(SYSDATE,'MM') + ROWNUM - 1 dt
FROM DUAL
CONNECT BY ROWNUM <= TO_NUMBER(TO_CHAR(LAST_DAY(SYSDATE),'DD'));

快速選型表

場景建議寫法版本
簡單 Top-NWHERE ROWNUM <= N所有
分頁(固定頁大小)子查詢 + ROWNUM rn + BETWEEN所有
分頁(12c+)OFFSET ... FETCH NEXT ...12c+
分組 Top-NROW_NUMBER() OVER (PARTITION BY ... ORDER BY ...)9i+
需保證正確排序子查詢先 ORDER BY 再 ROWNUM所有

掌握 ROWNUM 規則與 ROW_NUMBER() 分組能力,即可應付 Oracle 所有分頁與 Top-N 需求,避開「先取再排」的隱形 Bug。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved