2012-06-25 16 views
85

Jaka jest różnica między funkcjami RANK() i DENSE_RANK()? Jak znaleźć n-tą wynagrodzenie w poniższej tabeli emptbl?Jaka jest różnica między funkcjami RANK() i DENSE_RANK() w 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 

Jeśli w tabeli danych o nulls, co się stanie, jeśli chcę, aby dowiedzieć się nth pensję?

Odpowiedz

146

RANK daje ranking w zamówionej partycji. Więzi mają przypisaną tę samą rangę, a kolejne rankingi są pomijane. Tak więc, jeśli masz 3 przedmioty w rankingu 2, kolejna pozycja na liście będzie w rankingu 5.

DENSE_RANK ponownie daje ranking w uporządkowanej partycji, ale rankingi są następujące po sobie. Żadne rangi nie są pomijane, jeśli istnieją rangi z wieloma przedmiotami.

Co do wartości null, zależy to od klauzuli ORDER BY. Oto prosty skrypt testowy można grać, aby zobaczyć co się dzieje:

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 do dobrego wyjaśnienia i przykłady.

+6

bardzo dobry id ea używać select union all from dual do generowania przykładowych danych bez tworzenia tabeli –

+0

@ Jean-ChristopheBlanchard chociaż można równie łatwo użyć klauzuli "wartości". – Wildcard

+1

@Wildcard W PG, tak. W Oracle: * no *. Przynajmniej nie jako 11. Nie natknąłem się jeszcze na 12 w 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() -> używany do generowania numeru seryjnego

Dense_rank() da ciągłe rangę ale ranga pominie rangę w przypadku zderzenia rangi.

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. Zasadniczo, można spojrzeć na nią jako takie:

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; 

Powyższy przyniesie:

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

W słowach

  • ROW_NUMBER() atrybuty unikalną wartość do każdego rzędu
  • RANK() przypisuje samą liczbę rzędów na taką samą wartość, pozostawiając „dziury”
  • DENSE_RANK() atrybuty samą liczbę rzędów na tę samą wartość, nie pozostawiając „dziury”
+1

To jest tak dobre :) – nanosoft

+0

Błąd: Błąd SQL: ORA-00923: FROM nie znaleziono słowa gdzie oczekiwano – zloctb

+0

@zloctb: Tak, dziękuję. Naprawiony –

1

Jedyna różnica pomiędzy RANK () i DENSE_RANK() funkcje w przypadkach, gdy istnieje "krawat"; tj. w przypadkach, gdy wiele wartości w zestawie ma taki sam ranking. W takich przypadkach funkcja RANK() przypisze nie kolejne wartości "rang" do wartości w zestawie (co spowoduje odstępy między wartościami liczb całkowitych w przypadku remisu), natomiast funkcja DENSE_RANK() przypisze kolejne rangi do wartości w tabeli. set (więc nie będzie żadnych przerw między wartościami rankingowymi liczb całkowitych w przypadku remisu).

Weźmy na przykład zestaw {25, 25, 50, 75, 75, 100}. Dla takiego zestawu funkcja RANK() zwróci {1, 1, 3, 4, 4, 6} (zwróć uwagę, że wartości 2 i 5 są pomijane), natomiast funkcja DENSE_RANK() zwróci {1,1,2,3, 3,4}.

2

pozycja(): Służy do rangowania rekordu w grupie wierszy.

dense_rank(): Funkcja DENSE_RANK działa podobnie do funkcji RANK, z wyjątkiem tego, że przypisuje kolejne szeregi.

Zapytanie -

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

Wyjście -

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

Zapytanie -

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

Wyjście -

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