Pra não ficar só no bláblablá, vamos a um exemplo - suponha que eu quero
agrupar por departamento, e para cada departamento eu quero ordenar por Salário
e mostrar os 3 primeiros salários, e tenho os seguintes dados :
scott@DESENV:SQL>select deptno, empno, sal from emp order by deptno, sal;
DEPTNO EMPNO SAL
--------- --------- ---------
10 7934 1300
10 7782 2450
10 7839 5000
20 7369 800
20 7876 1100
20 7566 2975
20 7788 3000
20 7902 3000
30 7900 950
30 7654 1250
30 7521 1250
30 7844 1500
30 7499 1600
30 7698 2850
14 linhas selecionadas.
PERCEBA que para o departamento 30 o segundo e o terceiro salário empataram,
ambos recebem 1250... Aí vem a pergunta, o que faço nesse caso ? Se vc quer
simplesmente mostrar os 3 salarios ordenados SEM se importar com desempates
seria simplesmente atribuir um número sequencial pra cada registro dentro do
grupo E filtrar depois onde esse número seja < 4 (ou <= 3, como preferir)....
Tipo :
scott@DESENV:SQL>SELECT deptno,
2 empno,
3 sal,
4 row_number() OVER (PARTITION BY deptno ORDER BY sal) AS NUM_REG
5* FROM emp;
DEPTNO EMPNO SAL NUM_REG
--------- --------- --------- ---------
10 7934 1300 1
10 7782 2450 2
10 7839 5000 3
20 7369 800 1
20 7876 1100 2
20 7566 2975 3
20 7788 3000 4
20 7902 3000 5
30 7900 950 1
30 7654 1250 2
30 7521 1250 3
30 7844 1500 4
30 7499 1600 5
30 7698 2850 6
14 linhas selecionadas.
scott@DESENV:SQL>
==> Tá vendo ? Os registros foram AGRUPADOS por DEPTNO e o NUM_REG é resetado a
cada vez que muda de DEPTO, essa lógica é Automágica nas funções analíticas....
Vamos filtrar por esse número, para receber só os 3 primeiros registros do
grupo ? Isso vai ficar :
scott@DESENV:SQL>select * from (
2 SELECT deptno,
3 empno,
4 sal,
5 row_number() OVER (PARTITION BY deptno ORDER BY sal) AS NUM_REG
6 FROM emp )
7* WHERE NUM_REG < 4;
DEPTNO EMPNO SAL NUM_REG
--------- --------- --------- ---------
10 7934 1300 1
10 7782 2450 2
10 7839 5000 3
20 7369 800 1
20 7876 1100 2
20 7566 2975 3
30 7900 950 1
30 7521 1250 2
30 7654 1250 3
9 linhas selecionadas.
scott@DESENV:SQL>
Simples, só encapsulei o agrupamento num sub-query para poder aplicar um WHERE
nele... Não é ? SE é isso que vc quer (simplesmente listar os 3 primeiros
dentro de cada grupo, SEM se preocupar com empates) tá feita a fofoca...
Já se neste meu exemplo eu quisesse que quando houvesse empate (por exemplo, no
depto 30 a terceira linha fosse o salário 1500, desconsiderando o empate em
1250) aí eu usaria algo tipo DENSE_RANK :
scott@DESENV:SQL>SELECT deptno,
2 empno,
3 sal,
4 dense_rank() OVER (PARTITION BY deptno ORDER BY sal) AS NUM_REG
5* FROM emp
scott@DESENV:SQL>/
DEPTNO EMPNO SAL NUM_REG
--------- --------- --------- ---------
10 7934 1300 1
10 7782 2450 2
10 7839 5000 3
20 7369 800 1
20 7876 1100 2
20 7566 2975 3
20 7788 3000 4
20 7902 3000 4
30 7900 950 1
30 7654 1250 2
30 7521 1250 2
30 7844 1500 3
30 7499 1600 4
30 7698 2850 5
14 linhas selecionadas.
scott@DESENV:SQL>
==>> PERCEBA que no departamento 30 a segunda posição foi um empate, ambos
'dividiram o pódio' na medalha de prata....Sacou ?? É ISSO que eu solicitei que
vc verificasse com teu Analista pra saber se é o que ele quer - via de regra,
99,99% das vezes quando neguim fala em N primeiros ou N últimos registros não
pensam nesses pontos de DESEMPATE....
[]s
Chiappa