2012-06-25 41 views
85

¿Cuál es la diferencia entre las funciones RANK() y DENSE_RANK()? ¿Cómo saber el n-ésimo salario en la siguiente tabla emptbl?¿Cuál es la diferencia entre las funciones RANK() y DENSE_RANK() en 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 

Si en los datos de la tabla que tienen nulls, lo que sucederá si yo quiero averiguar nth salario?

Respuesta

146

RANK le da la clasificación dentro de su partición ordenada. Se asigna a los lazos el mismo rango, con las siguientes clasificaciones omitidas. Por lo tanto, si tiene 3 elementos en el rango 2, el siguiente rango aparecerá en el ranking 5.

DENSE_RANK nuevamente le da el ranking dentro de su partición ordenada, pero los rangos son consecutivos. No se omiten los rangos si hay rangos con varios elementos.

En cuanto a los valores nulos, depende de la cláusula ORDER BY. Aquí es un simple script de prueba se puede jugar con ver lo que sucede:

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 a una buena explicación y algunos ejemplos.

+6

muy bueno Identificación ea usar select union all desde dual para generar datos de muestra sin crear ninguna tabla –

+0

@ Jean-ChristopheBlanchard aunque también podría usar una cláusula 'values'. – Wildcard

+1

@Wildcard En PG, sí. En Oracle, * no *. Al menos no a partir de 11. Todavía no me he encontrado con 12 en prod. – 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() -> Se utiliza para generar el número de serie

Dense_rank() dará rango continuo, sino rango se saltará rango en caso de choque de 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. Esencialmente, usted puede verlo como tales:

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; 

Lo anterior dará lugar a:

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

En palabras

  • ROW_NUMBER() atribuye un valor único para cada fila
  • RANK() atribuye el mismo número de fila en el mismo valor, dejando "huecos"
  • DENSE_RANK() los mismos atributos de número de fila en el mismo valor, sin dejar "huecos"
+1

que es tan bueno :) – nanosoft

+0

de error: Error de SQL: ORA-00923: DE palabra clave no se encuentra en espera – zloctb

+0

@zloctb: Sí, gracias. Fijo –

1

La única diferencia entre el rango () y DENSE_RANK() funciones es en los casos donde hay un "empate"; es decir, en los casos en que los valores múltiples en un conjunto tienen la misma clasificación. En tales casos, RANK() asignará "rangos" no consecutivos a los valores en el conjunto (dando como resultado espacios entre los valores de clasificación enteros cuando hay un empate), mientras que DENSE_RANK() asignará rangos consecutivos a los valores en el establecer (por lo que no habrá espacios vacíos entre los valores de clasificación de enteros en el caso de un empate).

Por ejemplo, considere el conjunto {25, 25, 50, 75, 75, 100}. Para dicho conjunto, RANK() devolverá {1, 1, 3, 4, 4, 6} (tenga en cuenta que los valores 2 y 5 se saltan), mientras que DENSE_RANK() devolverá {1,1,2,3, 3,4}.

2

rank(): Se utiliza para clasificar un registro dentro de un grupo de filas.

dense_rank(): La función DENSE_RANK actúa como la función RANK excepto que asigna rangos consecutivos.

consultas -

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

salida -

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

consultas -

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

salida -

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