sql >> Database >  >> RDS >> Oracle

RANK, DENSE_RANK en ROW_NUMBER functies in Oracle

Oracle Analytic-functies berekenen een totale waarde op basis van een groep rijen, window genaamd, die het rijbereik bepaalt dat wordt gebruikt om de berekeningen voor de huidige rij uit te voeren. Hieronder volgen de meest gebruikte analytische functies.
– RANK, DENSE_RANK en ROW_NUMBER
– LAG en LEAD
– FIRST_VALUE en LAST_VALUE

Ik zou het hebben over de analysefuncties RANK, DENSE_RANK en ROW_NUMBER. Ze lijken veel op elkaar en we moeten ze gebruiken op basis van de vereiste. Ik zou ook het verschil tussen beide uitleggen

Hier is de algemene syntaxis

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

ROW_NUMBER functie in Oracle

ROW_NUMBER wijst een uniek nummer toe aan elke rij van hetzelfde venster in de volgorde van rijen gespecificeerd door order_by_clause.

Laten we eerst voorbeeldgegevens maken

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.

RANK-functie in Oracle

RANG is bijna hetzelfde als ROW_NUMBER, maar rijen met gelijke waarden, met in hetzelfde venster, waarvoor de volgorde per clausule is opgegeven, krijgen dezelfde rangorde, maar de volgende rij krijgt RANK volgens 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.

Dense_rank-functie in Oracle

DENSE_RANK is bijna hetzelfde als de RANK, maar laat geen ruimte tussen rijen als een of meer waarden hetzelfde zijn. Zoals in het volgende voorbeeld ontvangt TURNER naast WARD in dezelfde groep 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.

We kunnen ze alle drie ook in de enkele zoekopdracht plaatsen

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.

We kunnen de functie Row_number en RANK gebruiken bij het verwijderen van de duplicerende rijen

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

Deze functies zijn erg handig voor  voor top-N- en bottom-N-query's.

De onderstaande SQL kan worden gebruikt om het hoogste salaris in elke afdeling te vinden

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

Ik hoop dat je uitleg wilt over RANK, DENSE_RANK en ROW_NUMBER zoals Oracle Analytic-functies en hoe we in de query de gegevens kunnen analyseren. We moeten heel voorzichtig zijn bij het gebruik van deze functies in de query's, anders zou het resultaat anders zijn.

Verwante artikelen

LEAD-functie in Oracle
Analytische functies in Oracle
Oracle Interviewvragen
Oracle Set-operators
Oracle Sql-zelfstudie
Dense Rank Oracle-documentatie


  1. Optimalisatie van MySQL-zoekopdrachten met likes en jokertekens

  2. Ontvang de huidige lokale tijd van elk land in PL/SQL

  3. Gegevens opslaan in de onDestroy-methode van activiteit

  4. Kan het schema niet verwijderen, omdat het niet bestaat of omdat je geen toestemming hebt. - SQL Server / TSQL-zelfstudie, deel 29