[Oracle] ROW_NUMBER()を使った行番号表示の応用 | Archive Redo Blog

Archive Redo Blog

DBエンジニアのあれこれ備忘録

ROW_NUMBER()関数を使うと結果セットに対して行番号を振ることができますが、PARTITION BY句を使うと、PARTITION BY句で指定した列の値ごとに行番号が振られます。


例えば、部署(deptno)ごとに給料(sal)の多い者順に行番号を振る場合、以下のようになります。

SELECT DEPTNO, EMPNO, ENAME, SAL, ROW_NUMBER() 
  OVER ( PARTITION BY DEPTNO ORDER BY SAL DESC ) ROW# 
  FROM EMP;

    DEPTNO      EMPNO ENAME                       SAL       ROW#
---------- ---------- -------------------- ---------- ----------
        10       7839 KING                       5000          1
        10       7782 CLARK                      2450          2
        10       7934 MILLER                     1300          3
        20       7902 FORD                       3000          1
        20       7566 JONES                      2975          2
        20       7369 SMITH                       800          3
        30       7698 BLAKE                      2850          1
        30       7499 ALLEN                      1600          2
        30       7844 TURNER                     1500          3
        30       7521 WARD                       1250          4
        30       7654 MARTIN                     1250          5
        30       7900 JAMES                       950          6

行番号でなく、ランキングを表示したい場合は、RANK()を使います。

SELECT DEPTNO, EMPNO, ENAME, SAL, RANK() 
  OVER ( PARTITION BY DEPTNO ORDER BY SAL DESC ) ROW# 
  FROM EMP;

    DEPTNO      EMPNO ENAME                       SAL       ROW#
---------- ---------- -------------------- ---------- ----------
        10       7839 KING                       5000          1
        10       7782 CLARK                      2450          2
        10       7934 MILLER                     1300          3
        20       7902 FORD                       3000          1
        20       7566 JONES                      2975          2
        20       7369 SMITH                       800          3
        30       7698 BLAKE                      2850          1
        30       7499 ALLEN                      1600          2
        30       7844 TURNER                     1500          3
        30       7521 WARD                       1250          4
        30       7654 MARTIN                     1250          4
        30       7900 JAMES                       950          6

RANK()の場合、同値の場合に同じ番号になるというところがROW_NUMBER()と異なります。

また、このように番号を付けた上で、指定した番号の範囲のレコードだけを抽出したい場合は以下のようにします。

SELECT * FROM ( 
  SELECT DEPTNO, EMPNO, ENAME, SAL, ROW_NUMBER() 
    OVER ( PARTITION BY DEPTNO ORDER BY SAL DESC ) ROW# 
    FROM EMP 
  ) 
  WHERE ROW# BETWEEN 2 AND 5;

    DEPTNO      EMPNO ENAME                       SAL       ROW#
---------- ---------- -------------------- ---------- ----------
        10       7782 CLARK                      2450          2
        10       7934 MILLER                     1300          3
        20       7566 JONES                      2975          2
        20       7369 SMITH                       800          3
        30       7499 ALLEN                      1600          2
        30       7844 TURNER                     1500          3
        30       7521 WARD                       1250          4
        30       7654 MARTIN                     1250          5
この場合、2番目から5番目を抽出しています。



【関連エントリ】
[Oracle] 擬似列ROWNUMの利用 2004/09/16
[Oracle] ROW_NUMBER()を使った行番号表示の応用 2004/10/20