OracleのRANK()関数とDENSE_RANK()関数の違いは何ですか?


150

RANK()DENSE_RANK()関数の違いは何ですか?次のemptbl表のn番目の給与を調べる方法は?

DEPTNO  EMPNAME    SAL
------------------------------
10       rrr    10000.00
11       nnn    20000.00
11       mmm    5000.00
12       kkk    30000.00
10       fff    40000.00
10       ddd    40000.00
10       bbb    50000.00
10       ccc    50000.00

テーブルデータにがある場合、給与nullsを知りたい場合はどうなりnthますか?

回答:


242

RANKは、順序付けされたパーティション内のランキングを提供します。タイには同じランクが割り当てられ、次のランクはスキップされます。したがって、ランク2に3つのアイテムがある場合、次にリストされるランクは5になります。

DENSE_RANKにより、順序付けされたパーティション内のランキングが再び提供されますが、ランクは連続しています。複数のアイテムを持つランクがある場合、ランクはスキップされません。

nullに関しては、ORDER BY句に依存します。これは、何が起こるかを確認するために使用できる簡単なテストスクリプトです。

with q as (
select 10 deptno, 'rrr' empname, 10000.00 sal from dual union all
select 11, 'nnn', 20000.00 from dual union all
select 11, 'mmm', 5000.00 from dual union all
select 12, 'kkk', 30000 from dual union all
select 10, 'fff', 40000 from dual union all
select 10, 'ddd', 40000 from dual union all
select 10, 'bbb', 50000 from dual union all
select 10, 'xxx', null from dual union all
select 10, 'ccc', 50000 from dual)
select empname, deptno, sal
     , rank() over (partition by deptno order by sal nulls first) r
     , dense_rank() over (partition by deptno order by sal nulls first) dr1
     , dense_rank() over (partition by deptno order by sal nulls last) dr2
 from q; 

EMP     DEPTNO        SAL          R        DR1        DR2
--- ---------- ---------- ---------- ---------- ----------
xxx         10                     1          1          4
rrr         10      10000          2          2          1
fff         10      40000          3          3          2
ddd         10      40000          3          3          2
ccc         10      50000          5          4          3
bbb         10      50000          5          4          3
mmm         11       5000          1          1          1
nnn         11      20000          2          2          2
kkk         12      30000          1          1          1

9 rows selected.

良い説明といくつかの例へのリンクがあります。


14
すべてをデュアルから選択ユニオンを使用して、テーブルを作成せずにサンプルデータを生成することは非常に良い考えです
Jean-Christophe Blanchard

@ Jean-ChristopheBlanchardでもvalues句を簡単に使用できます。
ワイルドカード

1
@ワイルドカードPGでは、はい。Oracleでは、ありません。少なくとも11の時点ではありません。製品版ではまだ12に達していません。
jpmc26 2017年

from dualRedshiftでこのデータを生成するために削除
Gaurav 2017

4
Ivan、RANKは、私が自分の前にいるすべての人に対して相対的であるという考えを私に与えます。DENSE_RANKは絶対ランクを教えてくれます。私の給料は2番目に高いかもしれませんが、私の前に100人がいる可能性があります。どちらが良いかは、私が答えている質問に依存します。
DCookie

93

この記事では、うまく説明しています。基本的に、次のように見ることができます。

CREATE TABLE t AS
SELECT 'a' v FROM dual UNION ALL
SELECT 'a'   FROM dual UNION ALL
SELECT 'a'   FROM dual UNION ALL
SELECT 'b'   FROM dual UNION ALL
SELECT 'c'   FROM dual UNION ALL
SELECT 'c'   FROM dual UNION ALL
SELECT 'd'   FROM dual UNION ALL
SELECT 'e'   FROM dual;

SELECT
  v,
  ROW_NUMBER() OVER (ORDER BY v) row_number,
  RANK()       OVER (ORDER BY v) rank,
  DENSE_RANK() OVER (ORDER BY v) dense_rank
FROM t
ORDER BY v;

上記の結果は次のようになります。

+---+------------+------+------------+
| V | ROW_NUMBER | RANK | DENSE_RANK |
+---+------------+------+------------+
| a |          1 |    1 |          1 |
| a |          2 |    1 |          1 |
| a |          3 |    1 |          1 |
| b |          4 |    4 |          2 |
| c |          5 |    5 |          3 |
| c |          6 |    5 |          3 |
| d |          7 |    7 |          4 |
| e |          8 |    8 |          5 |
+---+------------+------+------------+

言葉で

  • ROW_NUMBER() 各行に一意の値を割り当てます
  • RANK() 同じ行番号を同じ値に割り当て、「穴」を残す
  • DENSE_RANK() 同じ行番号を同じ値に割り当て、「穴」を残さない

エラー:SQLエラー:ORA-00923:FROMキーワードが予期した場所に見つかりません
zloctb

9
SELECT empno,
       deptno,
       sal,
       RANK() OVER (PARTITION BY deptno ORDER BY sal) "rank"
FROM   emp;

     EMPNO     DEPTNO        SAL       rank
---------- ---------- ---------- ----------
      7934         10       1300          1
      7782         10       2450          2
      7839         10       5000          3
      7369         20        800          1
      7876         20       1100          2
      7566         20       2975          3
      7788         20       3000          4
      7902         20       3000          4
      7900         30        950          1
      7654         30       1250          2
      7521         30       1250          2
      7844         30       1500          4
      7499         30       1600          5
      7698         30       2850          6


SELECT empno,
       deptno,
       sal,
       DENSE_RANK() OVER (PARTITION BY deptno ORDER BY sal) "rank"
FROM   emp;

     EMPNO     DEPTNO        SAL       rank
---------- ---------- ---------- ----------
      7934         10       1300          1
      7782         10       2450          2
      7839         10       5000          3
      7369         20        800          1
      7876         20       1100          2
      7566         20       2975          3
      7788         20       3000          4
      7902         20       3000          4
      7900         30        950          1
      7654         30       1250          2
      7521         30       1250          2
      7844         30       1500          3
      7499         30       1600          4
      7698         30       2850          5

8

ランク():行のグループ内でレコードをランク​​付けするために使用されます。

密度ランク():DENSE_RANK関数は、連続するランクを割り当てることを除いて、RANK関数と同じように機能します。

クエリ-

select 
    ENAME,SAL,RANK() over (order by SAL) RANK
from 
    EMP;

出力-

+--------+------+------+
| ENAME  | SAL  | RANK |
+--------+------+------+
| SMITH  |  800 |    1 |
| JAMES  |  950 |    2 |
| ADAMS  | 1100 |    3 |
| MARTIN | 1250 |    4 |
| WARD   | 1250 |    4 |
| TURNER | 1500 |    6 |
+--------+------+------+

クエリ-

select 
    ENAME,SAL,dense_rank() over (order by SAL) DEN_RANK
from 
    EMP;

出力-

+--------+------+-----------+
| ENAME  | SAL  |  DEN_RANK |
+--------+------+-----------+
| SMITH  |  800 |         1 |
| JAMES  |  950 |         2 |
| ADAMS  | 1100 |         3 |
| MARTIN | 1250 |         4 |
| WARD   | 1250 |         4 |
| TURNER | 1500 |         5 |
+--------+------+-----------+

2
select empno
       ,salary
       ,row_number() over(order by salary desc) as Serial
       ,Rank() over(order by salary desc) as rank
       ,dense_rank() over(order by salary desc) as denseRank
from emp ;

Row_number() ->シリアル番号の生成に使用

Dense_rank() ランクは連続しますが、ランクが衝突した場合はランクがスキップされます。


2

RANK()関数とDENSE_RANK()関数の唯一の違いは、「タイ」がある場合です。つまり、セット内の複数の値が同じランキングを持つ場合です。そのような場合、RANK()は連続していない「ランク」をセット内の値に割り当てます(結果として、同数の場合、整数のランキング値の間にギャップが生じます)。一方、DENSE_RANK()は、連続するランクを設定されます(タイの場合、整数のランキング値の間にギャップはありません)。

たとえば、セット{25、25、50、75、75、100}を考えます。そのようなセットの場合、RANK()は{1、1、3、4、4、6}を返します(値2と5はスキップされることに注意してください)が、DENSE_RANK()は{1,1,2,3、 3,4}。


1

Rank()SQL関数は、順序付けられた値のセット内のデータのランクを生成しますが、前のランクの次のランクはその特定の行のrow_numberです。一方、Dense_Rank()SQL関数は、row_numberを生成する代わりに次の数値を生成します。以下は、概念を明確にするSQLの例です。

Select ROW_NUMBER() over (order by Salary) as RowNum, Salary, 
RANK() over (order by Salary) as Rnk, 
DENSE_RANK() over (order by Salary) as DenseRnk from (
Select 1000 as Salary union all
Select 1000 as Salary union all
Select 1000 as Salary union all
Select 2000 as Salary union all
Select 3000 as Salary union all
Select 3000 as Salary union all
Select 8000 as Salary union all
Select 9000 as Salary) A

次の出力が生成されます。

----------------------------
RowNum  Salary  Rnk DenseRnk
----------------------------
1       1000    1   1
2       1000    1   1
3       1000    1   1
4       2000    4   2
5       3000    5   3
6       3000    5   3
7       8000    7   4
8       9000    8   5

0

ランクと密ランクは、分割されたデータセット内のランクを示します。

Rank():連続した整数を与えません。

Dense_rank():連続した整数値を提供します。

ここに画像の説明を入力してください

上記の図では、10008 zipのランクは、row_numberを考慮しているため、dense_rank()関数では2、rank()関数では24です。


0

Rank(), Dense_rank(), row_number() これらはすべてウィンドウ関数であり、最初は順序付けされた入力セットのウィンドウとして機能します。これらのウィンドウには、要件に基づいて異なる機能が関連付けられています。上記の3をHeres:

row_number()

で開始row_number()これは、これらの関連する窓関数の基礎を形成して。row_number()名前が示すように、適用される行のセットに一意の番号を付けます。各行にシリアル番号を付けるのと同じです。

Rank()

の転覆はとrow_number()言えますrank()。Rank()は、重複している順序付けられたセット行に同じシリアル番号を与えるために使用されますが、それでもrow_number()、以下のように、rank()の意味が重複した後のすべてのものと同じようにカウントを維持します。データ2の場合、row_number()= rank()は、両方が重複の形で異なるだけであることを意味します。

Data row_number() rank() dense_rank() 
    1         1                    1       1
    1         2                    1       1
    1         3                    1       1
    2         4                    4       2

最後に、

Dense_rank()は、名前がその密集度を示唆しているため、rank()の拡張バージョンです。これは、上記の例からわかるように、すべてのデータ1のrank()= ense_rank()ですが、データ2の場合のみ、フォーム2の形式が異なります。実際のデータではなく、以前のrank()からrank()の順序を維持します


0

RANK()関数とDENSE_RANK()関数の唯一の違いは、「タイ」がある場合です。つまり、セット内の複数の値が同じランキングを持つ場合です。そのような場合、RANK()は連続していない「ランク」をセット内の値に割り当てます(結果として、同数の場合、整数のランキング値の間にギャップが生じます)。一方、DENSE_RANK()は、連続するランクを設定されます(タイの場合、整数のランキング値の間にギャップはありません)。

たとえば、セット{30、30、50、75、75、100}を考えます。そのようなセットの場合、RANK()は{1、1、3、4、4、6}を返します(値2と5はスキップされることに注意してください)が、DENSE_RANK()は{1,1,2,3、 3,4}。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.