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