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

Oracle ROWNUM 與 ROWID 深度解析:偽欄位陷阱與正確用法

     編輯:Oracle 資料庫基礎

ROWNUM 與 ROWID 同為 Oracle 偽欄位,但本質截然不同。誤用 ROWNUM 是新手常見 Bug 來源。本文深度解析兩者差異、ROWNUM 陷阱成因、正確分頁寫法與 ROWID 實戰應用。

核心差異對照

特性ROWNUMROWID
本質查詢結果集的**邏輯序號**(1 起)資料列在資料檔中的**物理地址**(18 字元 Base64)
存在時機查詢執行時動態產生資料寫入時固定,除非行遷移/分區移動
可作為 WHERE 條件有嚴格限制(見下文)可自由比較、索引存取(隱含索引)
穩定性同一查詢重跑順序不變則相同極度穩定,可跨查詢/Session 定位同一行

ROWNUM 經典陷阱

陷阱 1:WHERE ROWNUM > 2 永遠無資料


SELECT * FROM t WHERE ROWNUM > 2;  -- 無結果

原因:Oracle 先取第一行 → ROWNUM=1 → 不符合 >2 → 捨棄 → 取第二行 → ROWNUM 重置為 1 → 仍不符合 → 無限循環無結果。

陷阱 2:WHERE ROWNUM = 2 也無資料

同理,第一行 ROWNUM=1 不符合被捨棄後,後續行 ROWNUM 永遠從 1 開始,永無機會等於 2。

陷阱 3:WHERE ROWNUM BETWEEN 2 AND 10 無資料

同理,ROWNUM 永遠從 1 起跳,無法跳過第一行。

ROWNUM 合法用法

需求正確寫法說明
前 N 筆WHERE ROWNUM <= N 或 WHERE ROWNUM < N+1包含 1 即可
第 M~N 筆(分頁)雙層嵌套 + 別名見下方標準分頁模板
單筆檢查WHERE ROWNUM = 1隱性游標常用

標準分頁模板(Oracle 11g/12c 通用)


SELECT * FROM (
  SELECT a.*, ROWNUM rn FROM (
    SELECT * FROM t ORDER BY id   -- 內層必須 ORDER BY 確保順序穩定
  ) a WHERE ROWNUM <= :end_row
) WHERE rn >= :start_row;
  • 內層 ROWNUM <= :end_row 先截取前端行數,外層再過濾起始行。
  • 內層查詢必須有別名 a,外層引用 rn。
  • Oracle 12c+ 可簡化為 OFFSET :start_row ROWS FETCH NEXT :page_size ROWS ONLY。

ROWID 實戰應用

1. 快速定位/刪除重複資料


DELETE FROM t
WHERE ROWID NOT IN (
  SELECT MIN(ROWID) FROM t GROUP BY col1, col2, col3  -- 保留每組第一行
);

2. 大量更新分批 COMMIT 避免 UNDO 爆滿


FOR r IN (SELECT ROWID rid FROM t WHERE cond) LOOP
  UPDATE t SET col = val WHERE ROWID = r.rid;
  IF MOD(cnt, 1000) = 0 THEN COMMIT; END IF;
END LOOP;
COMMIT;

3. 跨 Session 定位同一行(如鎖等待分析)


SELECT * FROM t WHERE ROWID = 'AAAP...';  -- 從 V$SESSION_WAIT 取得 ROWID

總結口訣

  • ROWNUM 是順序號,只能「取前」、不能「跳過」。
  • ROWID 是身分證,精準定位、跨查詢通用。
  • 分頁必用雙層嵌套(或 12c OFFSET),切勿嘗試單層 ROWNUM BETWEEN。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved