Oracle
 sql >> Baza danych >  >> RDS >> Oracle

Funkcje RANK, DENSE_RANK i ROW_NUMBER w Oracle

Funkcje Oracle Analytic obliczają wartość zagregowaną na podstawie grupy wierszy zwanej oknem, która określa zakres wierszy użytych do wykonania obliczeń dla bieżącego wiersza. Poniżej przedstawiono najczęściej używane funkcje analityczne.
– RANK, DENSE_RANK i ROW_NUMBER
– LAG i LEAD
– FIRST_VALUE i LAST_VALUE

Rozmawiałbym o funkcjach analitycznych RANK, DENSE_RANK i ROW_NUMBER. Mają one dość podobny charakter i musimy użyć ich na podstawie wymagań. Wyjaśniłbym również różnicę między nimi

Oto ogólna składnia

analytic_function([ arguments ]) OVER ([ query_partition_clause ] [ order_by_clause  ])

Funkcja ROW_NUMBER w Oracle

ROW_NUMBER przypisuje unikalny numer do każdego wiersza tego samego okna w uporządkowanej sekwencji wierszy określonej przez order_by_clause.

Najpierw utwórzmy przykładowe dane

CREATE TABLE "DEPT"
( "DEPTNO" NUMBER(2,0),
"DNAME" VARCHAR2(14),
"LOC" VARCHAR2(13),
CONSTRAINT "PK_DEPT" PRIMARY KEY ("DEPTNO")
)

CREATE TABLE "EMP"
( "EMPNO" NUMBER(4,0),
"ENAME" VARCHAR2(10),
"JOB" VARCHAR2(9),
"MGR" NUMBER(4,0),
"HIREDATE" DATE,
"SAL" NUMBER(7,2),
"COMM" NUMBER(7,2),
"DEPTNO" NUMBER(2,0),
CONSTRAINT "PK_EMP" PRIMARY KEY ("EMPNO"),
CONSTRAINT "FK_DEPTNO" FOREIGN KEY ("DEPTNO")
REFERENCES "DEPT" ("DEPTNO") ENABLE
);

SQL> desc emp
Name Null? Type
---- ---- -----
EMPNO NOT NULL NUMBER(4)
ENAME VARCHAR2(10)
JOB VARCHAR2(9)
MGR NUMBER(4)
HIREDATE DATE
SAL NUMBER(7,2)
COMM NUMBER(7,2)
DEPTNO NUMBER(2)

SQL> desc dept
Name Null? Type
---- ----- ----
DEPTNO NOT NULL NUMBER(2)
DNAME VARCHAR2(14)
LOC VARCHAR2(13)


insert into DEPT values(10, 'ACCOUNTING', 'NEW YORK');
insert into dept values(20, 'RESEARCH', 'DALLAS');
insert into dept values(30, 'RESEARCH', 'DELHI');
insert into dept values(40, 'RESEARCH', 'MUMBAI');
commit;

insert into emp values( 7839, 'Clark', 'MANAGER', 7839, to_date('9-6-2008','dd-mm-yyyy'), 28573, null, 10 );
insert into emp values( 7782, 'Clara', 'MANAGER', 7839, to_date('9-6-2008','dd-mm-yyyy'), 0, null, 10 );
insert into emp values( 7934, 'Blake', 'MANAGER', 7839, to_date('1-5-2007','dd-mm-yyyy'), 0, null, 10 );
insert into emp values( 7788, 'Scott', 'ANALYST', 7788, to_date('9-6-2012','dd-mm-yyyy'), 30000, null, 20 );
insert into emp values( 7902, 'Bill', 'ANALYST', 7832, to_date('9-6-2012','dd-mm-yyyy'), 30000, null, 20 );
insert into emp values( 7876, 'TPM', 'ANALYST', 7566, to_date('9-6-2017','dd-mm-yyyy'), 11000, null, 20 );
insert into emp values( 7369, 'TPM1', 'ANALYST', 7566, to_date('9-6-2017','dd-mm-yyyy'), 8000, null, 20 );

insert into emp values( 7698, 'A1', 'ANALYST', 7788, to_date('9-6-2017','dd-mm-yyyy'), 28500, null, 30 );
insert into emp values( 7499, 'A2', 'ANALYST', 7698, to_date('9-7-2017','dd-mm-yyyy'), 16000, null, 30 );
insert into emp values( 7844, 'A3', 'ANALYST', 7698, to_date('9-7-2017','dd-mm-yyyy'), 15000, null, 30 );
insert into emp values( 7654, 'A4', 'ANALYST', 7698, to_date('9-7-2017','dd-mm-yyyy'), 12500, null, 30 );
insert into emp values( 7521, 'A5', 'ANALYST', 7698, to_date('9-7-2017','dd-mm-yyyy'), 12500, null, 30 );
insert into emp values( 7900, 'A6', 'ANALYST', 77698, to_date('9-7-2017','dd-mm-yyyy'), 0, null, 30 );
commit;
SQL> desc emp
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 EMPNO                                     NOT NULL NUMBER(4)
 ENAME                                              VARCHAR2(10)
 JOB                                                VARCHAR2(9)
 MGR                                                NUMBER(4)
 HIREDATE                                           DATE
 SAL                                                NUMBER(7,2)
 COMM                                               NUMBER(7,2)
 DEPTNO                                             NUMBER(2)

SQL> select deptno ,count(*) from emp group by deptno;

    DEPTNO   COUNT(*)
---------- ----------
        30          6
        20          4
        10          3

SQL> select
deptno, ename, sal,
 row_number() over (partition by deptno order by sal) "row_number"
from
emp;

DEPTNO        ENAME       SAL    row_number
---------- ---------- ---------- ---------- 
10          CLARK          0        1 
10          MILLER         0        2
10          allen          28573    3
20          SMITH          8000     1
20          ADAMS          11000    2
20          SCOTT          30000    3
20          FORD           30000    4
30          JAMES          9500     1
30          MARTIN         12500    2
30          WARD           12500    3
30          TURNER         15000    4
30          ALLEN          16000    5
30          BLAKE          28500    6 

13 rows selected.

Funkcja RANK w Oracle

RANKING jest prawie taki sam jak ROW_NUMBER, ale wiersze o równych wartościach, w tym samym oknie, dla którego określono klauzulę order by otrzymują tę samą pozycję, ale następny wiersz otrzymuje RANK zgodnie z ROW_NUMBER.

SQL> select
deptno, ename, sal,
 rank() over (partition by deptno order by sal) "RANK"
from
emp;

DEPTNO        ENAME       SAL    RANK
---------- ---------- ---------- ---------- 
10          CLARK          0        1 
10          MILLER         0        2
10          allen          28573    3
20          SMITH          8000     1
20          ADAMS          11000    2
20          SCOTT          30000    3
20          FORD           30000    3
30          JAMES          9500     1
30          MARTIN         12500    2
30          WARD           12500    2
30          TURNER         15000    4
30          ALLEN          16000    5
30          BLAKE          28500    6 

13 rows selected.

Funkcja gęstego_rankingu w Oracle

DENSE_RANK jest prawie taka sama jak RANKING, ale nie pozostawia przerwy między wierszami, jeśli co najmniej jedna wartość jest taka sama. Jak w poniższym przykładzie TURNER obok WARD w tej samej grupie otrzymuje DENSE_RANK 3.

SQL> select
deptno, ename, sal,
 dense_rank() over (partition by deptno order by sal) "DENSE_RANK"
from
emp;

DEPTNO        ENAME       SAL    DENSE_RANK
---------- ---------- ---------- ---------- 
10          CLARK          0        1 
10          MILLER         0        2
10          allen          28573    3
20          SMITH          8000     1
20          ADAMS          11000    2
20          SCOTT          30000    3
20          FORD           30000    3
30          JAMES          9500     1
30          MARTIN         12500    2
30          WARD           12500    2
30          TURNER         15000    3
30          ALLEN          16000    4
30          BLAKE          28500    5 

13 rows selected.

Możemy również umieścić wszystkie trzy w pojedynczym zapytaniu

select
  deptno, ename, sal,
  row_number() over (partition by deptno order by sal) "row_number",
     rank() over (partition by deptno order by sal) "rank",
          dense_rank() over (partition by deptno order by sal) "dense_rank"
        from
          emp;

    DEPTNO ENAME             SAL row_number       rank dense_rank
---------- ---------- ---------- ---------- ---------- ----------
        10 CLARK               0          1          1          1
        10 MILLER              0          2          1          1
        10 allen           28573          3          3          2
        20 SMITH            8000          1          1          1
        20 ADAMS           11000          2          2          2
        20 SCOTT           30000          3          3          3
        20 FORD            30000          4          3          3
        30 JAMES            9500          1          1          1
        30 MARTIN          12500          2          2          2
        30 WARD            12500          3          2          2
        30 TURNER          15000          4          4          3
        30 ALLEN           16000          5          5          4
        30 BLAKE           28500          6          6          5

13 rows selected.

Możemy użyć funkcji Row_number i RANK do usunięcia zduplikowanych wierszy

delete from t
 where rowid IN ( select rid
                    from (select rowid rid, 
                                 row_number() over (partition by 
                         column_name
                                   order by rowid) rn
                            from t)
                   where rn <> 1);

Te funkcje są bardzo przydatne w przypadku zapytań o wartości N i N.

Poniższego SQL można użyć do znalezienia najwyższej pensji w każdym dziale

SQL> select * (select
deptno, ename, sal,
 row_number() over (partition by deptno order by sal) "row_number"
from
emp ) where row_number=1;

Mam nadzieję, że spodobają Ci się wyjaśnienia dotyczące RANK, DENSE_RANK i ROW_NUMBER, takich jak funkcje Oracle Analytic oraz sposoby wykorzystania w zapytaniu do analizy danych. Musimy być bardzo ostrożni podczas używania tych funkcji w zapytaniach, inaczej wynik byłby inny.

Powiązane artykuły

Funkcja LEAD w Oracle
Funkcje analityczne w Oracle
Pytania do wywiadu z Oracle
Oracle Set Operators
Samouczek Oracle Sql
Dokumentacja Oracle o gęstej randze


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. ORA-12505, TNS:listener nie zna obecnie SID podanego w connect des

  2. Konwersja bazy 36 do bazy 10 tylko przy użyciu SQL

  3. Oracle PL/SQL — kolekcje (tabele zagnieżdżone)

  4. ORA-12154 nie może rozpoznać podanego identyfikatora połączenia

  5. Znajdź długość najdłuższego wiersza w kolumnie w Oracle