As funções do Oracle Analytic calculam um valor agregado com base em um grupo de linhas chamado janela que determina o intervalo de linhas usado para realizar os cálculos para a linha atual. A seguir estão as funções analíticas mais usadas.
– RANK, DENSE_RANK e ROW_NUMBER
– LAG e LEAD
– FIRST_VALUE e LAST_VALUE
Eu estaria discutindo sobre as funções analíticas RANK, DENSE_RANK e ROW_NUMBER. Elas são de natureza bastante semelhante e precisamos usar com base no requisito. Eu também explicaria a diferença entre elas
Aqui está a sintaxe geral
analytic_function([ argumentos ]) OVER ([ query_partition_clause ] [ order_by_clause ])
função ROW_NUMBER no Oracle
ROW_NUMBER atribui um número exclusivo a cada linha da mesma janela na sequência ordenada de linhas especificada por order_by_clause.
Vamos primeiro criar dados de amostra
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") REFERÊNCIAS "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? Digite---- ----- ----DEPTNO NOT NULL NUMBER(2)DNAME VARCHAR2(14)LOC VARCHAR2(13)inserir em valores DEPT(10, 'ACCOUNTING', 'NEW YORK'); inserir em valores do departamento(20, 'PESQUISA', 'DALLAS');inserir nos valores do departamento(30, 'PESQUISA', 'DELHI');inserir nos valores do departamento(40, 'PESQUISA', 'MUMBAI');commit;inserir no valores emp( 7839, 'Clark', 'MANAGER', 7839, to_date('9-6-2008','dd-mm-aaaa'), 28573, null, 10 );inserir em valores emp( 7782, 'Clara ', 'MANAGER', 7839, to_date('9-6-2008','dd-mm-yyyy'), 0, null, 10 );inserir em valores emp( 7934, 'Blake', 'MANAGER', 7839 , to_date('1-5-2007','dd-mm-yyyy'), 0, null, 10 );inserir em valores emp( 7788, 'Scott', 'ANALYST', 7788, to_date('9-6 -2012','dd-mm-aaaa'), 30000, null, 20 );inserir em valores emp( 7902, 'Bill', 'ANALYST', 7832, to_date('9-6-2012','dd- mm-aaaa'), 30000, null, 20 ); inserir em valores emp( 7876, 'TPM', 'ANALYST', 7566, to_date('9-6-2017','dd-mm-yyyy'), 11000 , null, 20 ); insira nos valores emp( 7369, 'TPM1', 'ANALYST', 7566, to_date('9-6-2017',' dd-mm-aaaa'), 8000, null, 20 );inserir em valores emp( 7698, 'A1', 'ANALYST', 7788, to_date('9-6-2017','dd-mm-aaaa') , 28500, null, 30 ); insira nos valores emp ( 7499, 'A2', 'ANALYST', 7698, to_date('9-7-2017','dd-mm-yyyy'), 16000, null, 30 );inserir nos valores emp( 7844, 'A3', 'ANALYST', 7698, to_date('9-7-2017','dd-mm-aaaa'), 15000, null, 30 );inserir nos valores emp( 7654 , 'A4', 'ANALYST', 7698, to_date('9-7-2017','dd-mm-yyyy'), 12500, null, 30 );inserir em valores emp( 7521, 'A5', 'ANALYST ', 7698, to_date('9-7-2017','dd-mm-yyyy'), 12500, null, 30 );inserir em valores emp( 7900, 'A6', 'ANALYST', 77698, to_date(' 07-09-2017','dd-mm-aaaa'), 0, null, 30 );commit;
SQL> desc emp Nome Nulo? Tipo ----------------------------------------- -------- ---------------------------- 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> selecione deptno ,count(*) do grupo emp por deptno; DEPTNO COUNT(*)---------- ---------- 30 6 20 4 10 3SQL> selectdeptno, ename, sal, row_number() over (partição por deptno ordem por sal) "row_number"fromemp;DEPTNO ENAME SAL row_number---------- ---------- ---------- ---------- 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 Ala 12500 330 Turner 15000 430 Allen 16000 530 Blake 28500 6 13 filas selecionadas.
Função RANK no Oracle
CLASSIFICAÇÃO é quase igual a ROW_NUMBER, mas as linhas com valores iguais, na mesma janela, para as quais a cláusula order by é especificada, recebem a mesma classificação, mas a próxima linha recebe RANK conforme ROW_NUMBER.
SQL> selectdeptno, ename, sal, rank() over (partição por deptno ordem por 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 linhas selecionadas.
Função Dense_rank no Oracle
DENSE_RANK é quase igual ao RANK, mas não deixa espaço entre as linhas se um ou mais valores forem iguais. Como no exemplo a seguir, TURNER ao lado de WARD no mesmo grupo recebe DENSE_RANK 3.
SQL> selectdeptno, ename, sal, density_rank() over (partição por deptno ordem por 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 linhas selecionadas.
Podemos colocar todos os três em uma única consulta também
selecione deptno, ename, sal, row_number() sobre (partição por deptno ordem por sal) "row_number", rank() sobre (partição por deptno ordem por sal) "rank", denso_rank() sobre (partição por deptno ordem por sal) "dense_rank" de emp; DEPTNO ENAME SAL número_linha classificação classificação_densidade---------- ---------- ---------- ---------- ---- ------ ---------- 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 513 linhas selecionadas.>
Podemos usar a função Row_number e RANK para excluir as linhas duplicadas
delete from t where rowid IN ( selecione rid from (selecione rowid rid, row_number() over (partição por column_name ordem por rowid) rn from t) onde rn <> 1);
Essas funções são muito úteis para consultas de N superior e N inferior.
O SQL abaixo pode ser usado para encontrar o salário mais alto em cada departamento
SQL> selecione * (selectdeptno, ename, sal, row_number() over (partição por deptno ordem por sal) "row_number"fromemp ) onde row_number=1;
Espero que gostem da explicação sobre RANK, DENSE_RANK e ROW_NUMBER como funções do Oracle Analytic e como podemos usar na consulta para analisar os dados. Temos que ter muito cuidado ao usar essas funções nas consultas, senão o resultado seria diferente.
Artigos relacionados
Função LEAD no Oracle
Funções analíticas no oracle
Perguntas da entrevista do Oracle
Operadores de conjunto do Oracle
Tutorial do Oracle Sql
Documentação do Oracle de classificação densa