SQL Server/MySQL 使用 TOP N / LIMIT N,Oracle 需結合 ROWNUM 與 ORDER BY。本文詳細說明標準模式、排序陷阱、分頁擴展與 12c+ 新語法。
SELECT COL1, COL2, ... FROM (
SELECT COL1, COL2, ... FROM TABLE_NAME ORDER BY COL1, COL2 ...
) WHERE ROWNUM <= N;
資料:
ID NAME
01 FIRST
02 SECOND
03 THIRD
04 FORTH
05 FIFTH
06 SIXTH
07 SEVENTH
08 EIGHTH
09 NINTH
10 TENTH
11 LAST
查詢:
SELECT * FROM (
SELECT * FROM CUSTOMER ORDER BY NAME
) WHERE ROWNUM <= 3;
結果 (按 NAME 排序後前 3 筆):
ID NAME
08 EIGHTH
05 FIFTH
01 FIRST
ROWNUM 在 WHERE 階段分配,若寫成:
-- 錯誤:先取前 3 筆 (未排序) 再排序
SELECT * FROM CUSTOMER WHERE ROWNUM <= 3 ORDER BY NAME;
會先任意取 3 筆資料,再對這 3 筆排序 → 結果不正確。必須先排序 (子查詢),再套用 ROWNUM (外層)。
SELECT * FROM (
SELECT T.*, ROWNUM RN FROM (
SELECT * FROM CUSTOMER ORDER BY NAME
) T WHERE ROWNUM <= 20
) WHERE RN > 10;
-- 前 3 筆
SELECT * FROM CUSTOMER ORDER BY NAME FETCH FIRST 3 ROWS ONLY;
-- 第 11-20 筆
SELECT * FROM CUSTOMER ORDER BY NAME OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY;
WITH TIES 處理並列值CREATE INDEX IDX_CUST_NAME ON CUSTOMER(NAME); 避免全表排序SELECT /*+ FIRST_ROWS(10) */ ... 引導優化器選擇 Index Range ScanWHERE NAME > :last_name ORDER BY NAME FETCH FIRST 10)| 誤區 | 錯誤寫法 | 正確寫法 |
|---|---|---|
| 直接 WHERE ROWNUM | SELECT * FROM T ORDER BY C WHERE ROWNUM <= N | 子查詢排序 + 外層 ROWNUM |
| ROWNUM 從 0 開始 | WHERE ROWNUM BETWEEN 0 AND 9 | ROWNUM 從 1 起算 |
| DISTINCT + ROWNUM | SELECT DISTINCT * FROM T WHERE ROWNUM <= N | 子查詢 DISTINCT 排序 + 外層 ROWNUM |