Le funzioni di Oracle Analytic calcolano un valore aggregato in base a un gruppo di righe denominato finestra che determina l'intervallo di righe utilizzato per eseguire i calcoli per la riga corrente. Di seguito sono elencate le funzioni analitiche più utilizzate.
– RANK, DENSE_RANK e ROW_NUMBER
– LAG e LEAD
– FIRST_VALUE e LAST_VALUE
Discuterei delle funzioni di analisi RANK, DENSE_RANK e ROW_NUMBER. Sono di natura abbastanza simile e dobbiamo usarle in base ai requisiti. Spiegherei anche la differenza tra loro
Ecco la sintassi generale
funzione_analitica([ argomenti ]) OVER ([ query_partition_clause ] [ order_by_clause ])
Funzione ROW_NUMBER in Oracle
RIGA_NUMERO assegna un numero univoco a ciascuna riga della stessa finestra nella sequenza ordinata di righe specificata da order_by_clause.
Per prima cosa creiamo dati di esempio
CREA TABELLA "DEPT"( "DEPTNO" NUMBER(2,0),"DNAME" VARCHAR2(14),"LOC" VARCHAR2(13),VINCOLI "PK_DEPT" CHIAVE PRIMARIA ("DEPTNO"))CREA TABELLA " EMP"( "EMPNO" NUMBER(4,0),"ENAME" VARCHAR2(10),"JOB" VARCHAR2(9),"MGR" NUMBER(4,0),"HIREDATE" DATE,"SAL" NUMBER(7 ,2), NUMERO "COMM"(7,2), NUMERO "DEPTNO"(2,0), CONSTRAINT "PK_EMP" CHIAVE PRIMARIA ("EMPNO"), CONTRAINT "FK_DEPTNO" CHIAVE ESTERA ("DEPTNO") RIFERIMENTI "DEPT " ("DEPTNO") ENABLE);SQL> desc empName Null? Tipo---- ---- -----EMPNO NOT NULL NUMBER(4)ENAME VARCHAR2(10)JOB VARCHAR2(9)MGR NUMBER(4)HIREDATE DATESAL NUMBER(7,2)COMM NUMBER(7,2 )DEPTNO NUMBER(2)SQL> desc deptName Null? Digitare---- ----- ----DEPTNO NOT NULL NUMBER(2)DNAME VARCHAR2(14)LOC VARCHAR2(13)inserire nei valori DEPT(10, 'CONTABILITÀ', 'NEW YORK');inserire in valori di reparto(20, 'RESEARCH', 'DALLAS');inserire in valori di reparto(30, 'RESEARCH', 'DELHI');inserire valori di reparto(40, 'RESEARCH', 'MUMBAI');commit;inserire in emp values( 7839, 'Clark', 'MANAGER', 7839, to_date('9-6-2008','dd-mm-yyyy'), 28573, null, 10 );insert in emp values( 7782, 'Clara ', 'MANAGER', 7839, to_date('9-6-2008','dd-mm-yyyy'), 0, null, 10 );insert in emp values( 7934, 'Blake', 'MANAGER', 7839 , to_date('1-5-2007','dd-mm-yyyy'), 0, null, 10 );insert in emp values( 7788, 'Scott', 'ANALYST', 7788, to_date('9-6 -2012','dd-mm-yyyy'), 30000, null, 20 );insert in emp values( 7902, 'Bill', 'ANALYST', 7832, to_date('9-6-2012','dd- mm-aaaa'), 30000, null, 20 );insert in emp values( 7876, 'TPM', 'ANALYST', 7566, to_date('9-6-2017','dd-mm-yyyy'), 11000 , null, 20 );insert in emp values( 7369, 'TPM1', 'ANALYST', 7566, to_date('9-6-2017',' gg-mm-aaaa'), 8000, null, 20 );insert in emp values( 7698, 'A1', 'ANALYST', 7788, to_date('9-6-2017','dd-mm-yyyy') , 28500, null, 30 );insert in emp values( 7499, 'A2', 'ANALYST', 7698, to_date('9-7-2017','dd-mm-yyyy'), 16000, null, 30 );insert in emp values( 7844, 'A3', 'ANALYST', 7698, to_date('9-7-2017','dd-mm-aaaa'), 15000, null, 30 );insert in emp values( 7654 , 'A4', 'ANALYST', 7698, to_date('9-7-2017','dd-mm-yyyy'), 12500, null, 30 );insert in emp values( 7521, 'A5', 'ANALYST ', 7698, to_date('9-7-2017','dd-mm-yyyy'), 12500, null, 30 );insert in emp values( 7900, 'A6', 'ANALYST', 77698, to_date(' 9-7-2017','gg-mm-aaaa'), 0, null, 30 );commit;
SQL> desc emp Nome Null? Tipo ----------------------------------------- -------- ---------------------------- EMPNO NOT NULL NUMBER(4) ENAME VARCHAR2(10) JOB VARCHAR2(9) MGR NUMBER(4) DATA DI assunzione 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 3SQL> selectdeptno, ename, sal, row_number() over (partizione per reparto per ordine sal) "numero_riga"fromemp;DEPTNO ENAME SAL numero_riga---------- ---------- ---------- ---------- 10 Clark 0 1 10 Miller 0 210 Allen 28573 320 Smith 8000 120 Adams 11000 220 Scott 30000 320 Ford 30000 430 James 9500 130 Martin 12500 230 Ward 12500 330 Turner 15000 430 Allen 16000 530 Blake 28500 6 13 Dolle selezionate.
Funzione RANK in Oracle
GRADO è quasi uguale a ROW_NUMBER ma le righe con valori uguali, con nella stessa finestra, per cui è specificata la clausola order by ricevono lo stesso rango ma la riga successiva riceve RANK come da ROW_NUMBER.
SQL> selectdeptno, ename, sal, rank() over (partizione per reparto ordina per sal) "RANK"fromemp;DEPTNO ENAME SAL RANK---------- -------- -- ---------- ---------- 10 CLARK 0 1 10 MILLER 0 210 allen 28573 320 SMITH 8000 120 ADAMS 11000 220 SCOTT 30000 320 FORD 30000 330 JAMES 9500 130 MARTIN 12500 230 WARD 12500 230 TURNER 15000 430 ALLEN 16000 530 BLAKE 28500 6 13 file selezionati.
Funzione Dense_rank in Oracle
DENSE_RANK è quasi uguale al RANK, ma non lascia spazio tra le righe se uno o più valori sono uguali. Come nell'esempio seguente, TURNER accanto a WARD nello stesso gruppo riceve DENSE_RANK 3.
SQL> selectdeptno, ename, sal, dense_rank() over (partizione per reparto ordina per sal) "DENSE_RANK"fromemp;DEPTNO ENAME SAL DENSE_RANK---------- -------- -- ---------- ---------- 10 CLARK 0 1 10 MILLER 0 210 allen 28573 320 SMITH 8000 120 ADAMS 11000 220 SCOTT 30000 320 FORD 30000 330 JAMES 9500 130 MARTIN 12500 230 WARD 12500 230 TURNER 15000 330 ALLEN 16000 430 BLAKE 28500 5 13 file selezionati.
Possiamo anche mettere tutti e tre nella singola query
select deptno, ename, sal, row_number() sopra (partizione per reparto ordine per sal) "row_number", rank() sopra (partizione per reparto ordine per sal) "rank", dense_rank() sopra (partizione per reparto order by sal) "dense_rank" da emp; DEPTNO ENAME SAL numero_riga rango rango_denso---------- ---------- ---------- ---------- ---- ------ ---------- 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 3 file preselezionati 6 6 51>Possiamo usare Row_number e la funzione RANK per eliminare le righe duplicate
cancella da t dove rowid IN ( seleziona elimina da (seleziona rowid rid, row_number() su (partizione per nome_colonna ordina per rowid) rn da t) dove rn <> 1);Queste funzioni sono molto utili per per le prime N e le ultime N query.
L'SQL di seguito può essere utilizzato per trovare lo stipendio più alto in ogni reparto
SQL> select * (selectdeptno, ename, sal, row_number() over (partition by deptno order by sal) "row_number"fromemp ) dove row_number=1;Spero che ti piaccia la spiegazione su RANK, DENSE_RANK e ROW_NUMBER come le funzioni Oracle Analytic e come possiamo utilizzare nella query per analizzare i dati. Dobbiamo prestare molta attenzione durante l'utilizzo di queste funzioni nelle query, altrimenti il risultato sarebbe diverso.
Articoli correlati
Funzione LEAD in Oracle
Funzioni analitiche in Oracle
Domande su Oracle Interview
Oracle Set Operators
Tutorial Oracle Sql
Documentazione Oracle Dense rank