Qual è la differenza tra le funzioni RANK () e DENSE_RANK () in Oracle?


150

Qual è la differenza tra RANK()e le DENSE_RANK()funzioni? Come scoprire l'ennesimo stipendio nella emptbltabella seguente ?

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

Se nella tabella avessero i dati nulls, cosa succederà se voglio scoprire lo nthstipendio?

Risposte:


242

RANK ti fornisce la classifica all'interno della partizione ordinata. Ai pareggi viene assegnato lo stesso rango, con le classifiche successive ignorate. Quindi, se hai 3 oggetti al rango 2, il rango successivo elencato sarebbe classificato 5.

DENSE_RANK ti fornisce di nuovo la classifica all'interno della partizione ordinata, ma le classifiche sono consecutive. Nessun grado viene ignorato se sono presenti ranghi con più elementi.

Per quanto riguarda i null, dipende dalla clausola ORDER BY. Ecco un semplice script di prova con cui puoi giocare per vedere cosa succede:

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.

Ecco un link a una buona spiegazione e ad alcuni esempi.


14
ottima idea di utilizzare un unione selezionata tutta da doppia per generare dati di esempio senza creare alcuna tabella
Jean-Christophe Blanchard

@ Jean-ChristopheBlanchard anche se potresti usare altrettanto facilmente una valuesclausola.
Carattere jolly

1
@Wildcard In PG, sì. In Oracle, no . Almeno non da 11. Non ho ancora incontrato 12 in prod.
jpmc26,

Rimuovi from dualper generare questi dati in Redshift
Gaurav

4
Ivan, RANK mi dà un'idea di dove sono relativa a tutti quelli che mi stanno davanti. DENSE_RANK mi dice il grado assoluto. Potrei avere il secondo stipendio più alto, ma ci potrebbero essere 100 persone davanti a me. Quale è meglio dipende dalla domanda a cui sto rispondendo.
DCookie,

93

Questo articolo qui lo spiega bene. In sostanza, puoi guardarlo come tale:

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;

Quanto sopra produrrà:

+---+------------+------+------------+
| 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 |
+---+------------+------+------------+

In parole

  • ROW_NUMBER() attribuisce un valore univoco a ciascuna riga
  • RANK() attribuisce lo stesso numero di riga allo stesso valore, lasciando "buchi"
  • DENSE_RANK() attribuisce lo stesso numero di riga allo stesso valore, senza lasciare "buchi"

Errore: errore SQL: ORA-00923: parola chiave FROM non trovata dove previsto
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

rank () : viene utilizzato per classificare un record all'interno di un gruppo di righe.

dense_rank () : la funzione DENSE_RANK si comporta come la funzione RANK, tranne per il fatto che assegna gradi consecutivi.

Query -

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

Produzione -

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

Query -

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

Produzione -

+--------+------+-----------+
| 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() -> Utilizzato per generare il numero di serie

Dense_rank() darà un rango continuo ma il rango salterà il rango in caso di scontro di rango.


2

L'unica differenza tra le funzioni RANK () e DENSE_RANK () è nei casi in cui esiste un "pareggio"; vale a dire, nei casi in cui più valori in un set hanno lo stesso ranking. In questi casi, RANK () assegnerà "ranghi" non consecutivi ai valori nell'insieme (risultando in spazi vuoti tra i valori di classifica interi quando c'è un pareggio), mentre DENSE_RANK () assegnerà ranghi consecutivi ai valori nel set (quindi non ci saranno spazi tra i valori di classifica dei numeri interi in caso di pareggio).

Ad esempio, considera il set {25, 25, 50, 75, 75, 100}. Per un tale set, RANK () restituirà {1, 1, 3, 4, 4, 6} (nota che i valori 2 e 5 vengono saltati), mentre DENSE_RANK () restituirà {1,1,2,3, 3,4}.


1

Rank () La funzione SQL genera il rango dei dati all'interno del set di valori ordinato ma il rango successivo dopo il rango precedente è il numero di riga di quella particolare riga. D'altra parte, la funzione SQL Dense_Rank () genera il numero successivo invece di generare row_number. Di seguito è riportato l'esempio SQL che chiarirà il concetto:

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

Genererà il seguente output:

----------------------------
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

Il grado e il grado denso forniscono il grado nel set di dati partizionato.

Rank (): non ti dà numeri interi consecutivi.

Dense_rank (): ti dà numeri interi consecutivi.

inserisci qui la descrizione dell'immagine

Nell'immagine sopra, il grado di 10008 zip è 2 per la funzione dense_rank () e 24 per la funzione rank () poiché considera il numero di riga.


0

Rank(), Dense_rank(), row_number() Queste sono tutte funzioni della finestra, il che significa che inizialmente fungono da finestra su alcuni set di input ordinati. Queste finestre hanno diverse funzionalità associate in base al requisito. Ecco il 3 sopra:

row_number()

A partire da row_number()come questo costituisce la base di queste funzioni della finestra correlate. row_number()come suggerisce il nome, fornisce un numero univoco all'insieme di righe su cui è stato applicato. Simile a dare un numero seriale ad ogni riga.

Rank()

Si row_number()può dire una sovversione di rank(). Rank () viene utilizzato per assegnare lo stesso numero seriale a quelle righe di set ordinate che sono duplicati, ma mantiene comunque il conteggio mantenuto come simile a a row_number()per tutti quelli dopo il duplicato rank () che significa dal basso, ad es. Per i dati 2 row_number () = rank () significa che entrambi differiscono solo sotto forma di duplicati.

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

Finalmente,

Dense_rank () è una versione estesa di rank () poiché il nome suggerisce il suo denso perché come puoi vedere dall'esempio sopra rank () = dense_rank () per tutti i dati 1 ma solo che per i dati 2 differisce nella forma in cui esso mantiene l'ordine di rank () dal precedente rank () non i dati effettivi


0

L'unica differenza tra le funzioni RANK () e DENSE_RANK () è nei casi in cui esiste un "pareggio"; vale a dire, nei casi in cui più valori in un set hanno lo stesso ranking. In questi casi, RANK () assegnerà "ranghi" non consecutivi ai valori nell'insieme (risultando in spazi vuoti tra i valori di classifica interi quando c'è un pareggio), mentre DENSE_RANK () assegnerà ranghi consecutivi ai valori nel set (quindi non ci saranno spazi tra i valori di classifica dei numeri interi in caso di pareggio).

Ad esempio, considera l'insieme {30, 30, 50, 75, 75, 100}. Per un tale set, RANK () restituirà {1, 1, 3, 4, 4, 6} (nota che i valori 2 e 5 vengono saltati), mentre DENSE_RANK () restituirà {1,1,2,3, 3,4}.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.