Recurso para performance de análise de dados.
Quando utilizamos uma window function (w.f) definimos uma coluna dentro da cláusula OVER e esta coluna juntamente com a cláusula partition by cria um grupo que retorna para cada linha um resultado agrupado para aquele registro.
COMO FUNCIONA A WINDOW FUNCTION?
Suponhamos que uma consulta simples é realizada no banco AdventureWorks para retornar o ranking com as vendas do último ano corrente de acordo com cada região. Temos o seguinte resultado:
ENTENDENDO A CLÁUSULA OVER
Junto da cláusula OVER podemos usar funções de agregação como SUM, AVG, COUNT e etc tendo também três argumentos que podem participar desta cláusula:
- Partition By
- Order by
- ROW
Como a W.F atua linha por linha daquele subconjunto que foi gerado pela query que possui a cláusula over, o resultado é mais detalhado.
Em alguns casos, quando utilizamos função de agregação ou analíticas, não é possível ordenar dentro do over.
WINDOW FUNCTIONS COM FUNÇÕES DE AGREGAÇÃO
Utilizando as funções de agregação, conseguimos o maior nível de detalhamento e flexibilidade, podendo usar um grupo de linhas para que a função de agregação atue.
Temos a facilidade por exemplo de criar uma query que retorne uma coluna com o total absoluto, total por cliente, total por ano e etc. A gama de recursos que podemos utilizar com as W.F é extensa e tudo depende basicamente da cláusula OVER.
Veja este exemplo e como podemos criar um simples relatório.
A grande vantagem de utilizar W.F é para solucionar problemas que tínhamos com subqueries, quando havia necessidade de realizar queries mais analíticas.
Outro ponto interessante ao utilizar window functions é no que tange a sua ocorrência. Por ser processado após o from, where, group by ou having, ele só pode aparecer no select ou no order by. Eu prefiro utilizar no select.
Veja mais um exemplo da versatilidade e usabilidade das window function gerando uma análise de vendas gerais de todos os vendedores. Note que como são vendas totais, não há a cláusula partition by.
Uma dica: se utilizar uma CTE, a quantidade de análises possíveis se expande ainda mais.
Quando adicionamos o order by dentro de uma window function não estamos definindo apenas a ordem de exibição, lembrando que para garantir o ordenamento desejado, deve-se explicitar o order by ao final da query.
Mas utilizando o order by neste ponto, conseguimos trabalhar com uma opção chamada ‘frame’ que permite uma análise mais apurada, embora o escopo de ação passe a ser mais limitado.
Temos duas cláusulas quando especificamos o ‘frame’ de ação: rows e range.
T-SQL não suporta range.
Veja a query abaixo utilizando um exemplo simples de frame dentro da função de janela. Perceba que ela aplicada após o order by, como dito acima.
Quando utilizamos nesta query aplicando o frame por productid com a função de agregação de SUM, o que estamos dizendo para essa query é pra ela somar a linha atual com a próxima obtendo um ‘valor até o momento’. No exemplo abaixo, vamos ver o uso do frame rows.
Análise de running total value para produtos pedidos sendo o produto com id 787:
No próximo exemplo, como nosso order by é baseado na data todo o cálculo é feito sobre a perspectiva temporal e não simplesmente pelo id do vendedor. Este só está ali para critério de desempate.
Eu coloco a coluna subtotal para ser exibida no resultado apenas com o intuito de facilitar o entendimento da operação da query e da sua soma entre os valores.
Outra forma de determinar como o frame da w.f irá funcionar é utilizando o following na query com a seguinte sintaxe: ‘rows between current row and unbounded following‘.
Utilizando este modo de operação, nossa query passa a agir de forma inversa ao que vimos quando utilizamos ‘rows between unbounded preceding‘.
Veja esta query abaixo, utilizando ‘unbounded following‘ comparando com o preceding:
Veja nos dois destaques o seguinte:
Na coluna cust_preceding a query da linha 2 irá somar com a linha 1 e o resultado será exibido na coluna cust_preceding e este resultado da linha dois, irá somar com a linha três finalizando a soma dos pedidos para o cliente 11000.
já na coluna custfollowing o que temos é uma inversão e soma dos valores. Se perceberem o que ocorre, o resultado final da coluna cust_preceding 9115.13 virou o primeiro valor da coluna custfollowing. Isso ocorre porque quando utilizamos o frame declarando ‘unbounded following‘ ele pega o último valor da partição, joga para a primeira linha e vem somando os registros de baixo para cima.
Por ser um pouco confuso, o unbounded following não é tão utilizado. Tente dar preferência ao ‘rows unbounded preceding‘ é mais trivial.
OFFSET COMO OPÇÃO DE FRAME.
Dentro destas funções de janela e na utilização do frame, podemos especificar uma certa quantidade de linhas ao qual a função irá agir.
Dependendo do tipo de frame que utilizarmos definimos quantas linhas anteriores a atual e quantas linhas posteriores a atual uma determinada ação será executada.
Neste simples exemplo limitamos a operação apenas para uma linha anterior a atual e como na opção de framing estipulamos apenas ‘rows between 1 preceding and 1 preceding’, não houve soma, já que a linha atual está unicamente limitada a sua predecessora.
Agora, para realizar uma operação de soma limitando apenas a linha anterior, devemos declarar o framing da seguinte forma.
Veja que a linha dois somou com a linha um e a linha três somou com a dois, mas perceba que a soma não foi realizada com o resultado e sim, com o valor fixo da linha anterior.
Assim conseguimos limitar a ação de soma entre os resultados.
Outro exemplo de limitação de framing dentro das W.F se aplica somando a linha atual e a anterior, obtendo um resultado único utilizando ‘rows between 1 preceding and 1 following’.
Nesta query, a linha um como não possui uma anterior, soma apenas com a sua próxima linha tendo o resultado de 6344.86. A mesma lógica se aplica para a última linha
Já a linha dois faz exatamente o processo completo, somando com a sua anterior e seguinte, tendo o maior resultado.
Um fator importante a se destacar é que esta ação sofre uma limitação maior devido a query ser particionada pela coluna customerid o que limita a soma à apenas os clientes com id exatamente iguais.
Para efeito de demonstração, veja esta query com a mesma propriedade da anterior excluindo apenas o particionamento:
Agora podemos afirmar que as linhas estão somando com a anterior e próxima sem restrição de particionamento.
Este post teve o intuito de trazer luz para um recurso que permite grandes análises de dados e uma variedade no que tange a manipulação de resultados
Também mostrei como podemos limitar a ação de uma query com off set e como essa limitação afeta o resultado das funções de agregação
Link para o script do capítulo!
Espero que gostem, saúde!
‘