SQL> BREAK ON DEPTNO SKIP 1
SQL> SELECT deptno, ename, sal
2 FROM emp
3 ORDER BY deptno, sal DESC;
DEPTNO ENAME SAL
------ ---------- ----------
10 KING 5000
CLARK 2450
MILLER 1300
20 SCOTT 3000
FORD 3000
JONES 2975
ADAMS 1100
SMITH 800
30 BLAKE 2850
ALLEN 1600
TURNER 1500
WARD 1250
MARTIN 1250
JAMES 950
SELECT * FROM (
SELECT deptno,
ROW_NUMBER() OVER (PARTITION BY deptno ORDER BY sal DESC) AS rn,
ename, sal
FROM emp
)
WHERE rn <= 3;
DEPTNO RN ENAME SAL
------ -- ------ ------
10 1 KING 5000
2 CLARK 2450
3 MILLER 1300
20 1 SCOTT 3000
2 FORD 3000
3 JONES 2975
30 1 BLAKE 2850
2 ALLEN 1600
3 TURNER 1500
ROW_NUMBER() 產生的是「行號」,而非「排名」。
觀察部門 20:SCOTT 與 FORD 薪資同為 3000,但 RN 分別為 1、2。這代表:
ORDER BY 次序 (若無次序則不穩定)。RANK() 或 DENSE_RANK() (見下一篇)。
-- 將 3 參數化,搭配 Bind Variable
VARIABLE v_top NUMBER
EXEC :v_top := 3;
SELECT deptno, ename, sal
FROM (
SELECT deptno, ename, sal,
ROW_NUMBER() OVER (PARTITION BY deptno ORDER BY sal DESC) rn
FROM emp
)
WHERE rn <= :v_top;
PARTITION BY 欄位若有索引,Oracle 可避免全表排序 (WINDOW SORT PUSHED RANK)。PGA_AGGREGATE_TARGET 足夠,避免排序溢寫 Temp 表空間。FETCH FIRST N ROWS WITH TIES 簡化語法,但 ROW_NUMBER 相容性最佳。ROW_NUMBER() 是 **精準取得各群組 Top-N** 的利器,語意清晰:分區 → 排序 → 編號 → 過濾。掌握其「行號非排名」特性,避免業務誤判。下一篇將深入 RANK() / DENSE_RANK() 的同分處理差異。