2012-06-25 16 views
85

Qual è la differenza tra le funzioni RANK() e DENSE_RANK()? Come trovare l'ennesimo salario nella seguente tabella emptbl?Qual è la differenza tra le funzioni RANK() e DENSE_RANK() in oracle?

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 nei dati della tabella con nulls, che cosa accadrà se io voglio scoprire nth stipendio?

risposta

146

RANK ti fornisce la classifica all'interno della partizione ordinata. Le parità sono assegnate allo stesso valore, con la successiva (e) posizione (e) saltata. Quindi, se hai 3 articoli nella posizione 2, la classifica successiva sarà classificata 5.

DENSE_RANK ti offre di nuovo la classifica all'interno della partizione ordinata, ma i ranghi sono consecutivi. Nessuna truppa viene saltata se ci sono ranghi con più oggetti.

Per quanto riguarda i valori nulli, dipende dalla clausola ORDER BY. Ecco un semplice script di test si può giocare con 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. 

Here's a link ad una buona spiegazione e alcuni esempi.

+6

molto buona id ea usare select union all from dual per generare dati di esempio senza creare alcuna tabella –

+0

@ Jean-ChristopheBlanchard anche se si potrebbe facilmente usare una clausola 'values'. – Wildcard

+1

@Wildcard In PG, si. In Oracle, * no *. Almeno non a partire da 11. Non ho ancora incontrato 12 in prodotto. – jpmc26

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

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

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

This article here nicely explains it. In sostanza, si può guardare 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; 

È possibile che questo 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 unico a ogni riga
  • RANK() attributi lo stesso numero di riga per lo stesso valore, lasciando "buchi"
  • DENSE_RANK() attributi lo stesso numero di riga per lo stesso valore, senza lasciare "buchi"
+1

Questo è così buono :) – nanosoft

+0

Errore: Errore SQL: ORA-00923: parola chiave FROM non trovata dove previsto – zloctb

+0

@zloctb: Sì, grazie. Fisso –

1

L'unica differenza tra il RANK () e le funzioni DENSE_RANK() si trovano nei casi in cui è presente un "pareggio"; vale a dire, nei casi in cui più valori in un set hanno la stessa classifica. In questi casi, RANK() assegnerà "ranghi" non consecutivi ai valori dell'insieme (risultando in intervalli tra i valori di classifica interi quando c'è un pareggio), mentre DENSE_RANK() assegnerà ai ranghi consecutivi i valori nel set (quindi non ci saranno spazi tra i valori di classifica interi nel caso di un pareggio).

Ad esempio, considerare 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 sono saltati), mentre DENSE_RANK() restituirà {1,1,2,3, 3,4}.

2

rank(): è 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 che assegna i ranghi consecutivi.

Query -

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

uscita -

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

uscita -

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