21st Jul 2022 11 minutos de leitura Quando uso as funções de janela SQL? Tihomir Babic sql aprender sql window functions Índice O que são Funções de Janela (Window Functions) em SQL? Exemplo 1: Calcular o salário médio e comparar Individual Salário com a média Exemplo 2: Calcular o número médio de produtos vendidos por data e região Exemplo 3: Cálculo da Soma Cumulativa de Produtos Vendidos por Região Exemplo 4: Compare os preços das ações com os preços mínimo e máximo no mercado Exemplo 5: Calcular a porcentagem de mudança de preço e as médias móveis Você acha que o aprendizado Funções de Janela (Window Functions) em SQL pode ajudá-lo em seu trabalho? Você já ouviu um de seus colegas se gabando de usar as funções de janela SQL? Você conhece SQL básico mas não sabe muito, ou nada, sobre funções de janela? Se você quer aprender sobre funções de janela e como utilizá-las em um contexto empresarial, você está no lugar certo! Isto acontece com freqüência. Você alcança um certo nível de conhecimento e se sente como o rei (ou rainha) do mundo. Então, você ouve seus colegas falando sobre algo que você nunca ouviu falar (neste caso, funções de janela). Você imediatamente sente um pouco de vergonha de não conhecer já as funções de janela. Isto lhe soa familiar? Esta sensação não é agradável. Mas, pode ser uma coisa boa se isso o leva a perguntar o que são funções de janela. Então, você pode procurar no Google e encontrar alguns artigos úteis (como este aqui). De repente, o embaraço se transformará em empoderamento quando você perceber que as funções de janela não são misteriosas ou desaprendidas. Mais uma vez, você se sente como o rei do mundo. Ou rainha. Talvez até as duas coisas. Vamos em direção a este sentimento real! Tentarei não bombardear você com SQL. Em vez disso, vou dar a volta por cima. Darei vários exemplos comerciais do mundo real que lhe mostrarão o uso prático das funções de janela. O que são Funções de Janela (Window Functions) em SQL? Uma função de janela é, simplesmente, uma função que realiza cálculos através de um conjunto de linhas de tabela. O nome vem do fato de que o conjunto de linhas é chamado de janela ou moldura de janela. Aqui está um exemplo de como é uma janela. Na tabela abaixo, as janelas são marcadas por cores diferentes. A soma cumulativa é calculada para cada região, portanto, neste caso, as janelas são definidas por região. dateregionproducts_soldcumulative_sum 2020-03-01Region 19999 2020-03-02Region 198197 2020-03-03Region 143240 2020-03-01Region 29696 2020-03-02Region 259155 2020-03-03Region 229184 2020-03-01Region 37676 2020-03-02Region 350126 2020-03-03Region 370196 A sintaxe da função de janela é: window_function ([ALL] expression) OVER ([PARTITION BY partition_list] [ORDER BY order_list] [window_frame_clause]) A função de janela parte da sintaxe pode ser uma função agregada, como SUM() ou AVG(). Também pode ser outro tipo de função, como uma função analítica ou de ranking. A janela, ou o número de linhas sobre as quais determinados cálculos serão efetuados, é definida pela cláusula OVER(). PARTITION BY é uma cláusula opcional nas funções de janela. Ela define uma partição sobre a qual a função de janela realizará a operação. Se PARTITION BY não estiver definida, a função de janela executará a operação em toda a tabela. Você pode saber mais neste artigo. ORDER BY ordenará as linhas dentro de cada partição na ordem desejada. Se esta cláusula não estiver definida, então a cláusula utilizará a tabela inteira. A cláusula de quadro de janela define o número de linhas sobre as quais a função de janela irá operar usando duas palavras-chave. Uma é ROWS, usada para limitar o número de linhas, especificando o número de linhas que precedem ou seguem a linha atual. A outra é RANGE, usada para limitar o número de linhas, especificando um intervalo de valores com relação ao valor atual da linha. É por isso que a cláusula da janela também é chamada de cláusula ROW ou RANGE. Para aprender como usar esta sintaxe e praticá-la, o curso LearnSQL.com.br sobre funções de janela é o lugar para se ir. Além disso, se você estiver interessado em mais explicações sobre funções de janela, você pode encontrá-las aqui, juntamente com alguns exemplos. Passemos agora à parte divertida, resolvendo problemas! Exemplo 1: Calcular o salário médio e comparar Individual Salário com a média Este é um exemplo simples de um problema comum no mundo dos negócios. Digamos que há uma tabela employeeque contém dados sobre os salários dos funcionários. Ele consiste nas seguintes linhas: id - identificação única first_name - nome do funcionário last_name - sobrenome do funcionário department - departamento do funcionário salary - salário mensal do funcionário Usando estes dados, primeiro é preciso calcular o salário médio para toda a empresa. Em seguida, é preciso calcular quanto está acima ou abaixo do salário médio de cada funcionário. O seguinte código fará isso rapidamente: SELECT first_name, last_name, department, salary, AVG(salary) OVER() AS avg_salary, salary - AVG(salary) OVER() AS diff_salary FROM employee; Como você está familiarizado com SQL, você provavelmente reconhece pelo menos parte deste código. Ele seleciona first_name, last_name, department, e salary a partir da tabela employee. Nada de novo aqui. A linha AVG(salary) OVER() AS avg_salary calcula o salário médio na janela definida por OVER(). O resultado será mostrado na coluna avg_salary. A linha salary - AVG(salary) OVER() AS diff_salary calcula a diferença entre o salário de cada funcionário e o salário médio, O resultado será mostrado na coluna diff_salary. A execução deste código dará uma tabela útil. Veja um trecho dela abaixo: first_namelast_namedepartmentsalaryavg_salarydiff_salary EvangelinaChesshireTraining1,0152,469-1,454 JudDunkerleyLegal3,579.32,4691,111 EssaOdoSupport786.82,469-1,682 SaudraBolducServices609.22,469-1,860 GarveyJefferysSales4,600.22,4692,132 MaryjaneDumbrellServices590.92,469-1,878 RicaSiburnEngineering4,353.82,4691,885 ArlindaKilminsterSales3,891.92,4691,423 VerenaDevinnResearch and Development1,093.52,469-1,375 GerdaLegendreServices3,863.92,4691,395 Exemplo 2: Calcular o número médio de produtos vendidos por data e região Imagine que você está trabalhando em uma empresa que opera em três regiões. A gerência quer saber o número médio de produtos vendidos em cada região. Além disso, eles querem saber o número médio de produtos vendidos em geral para cada data. As funções de janela permitirão que você faça isso facilmente. Neste exemplo, os dados são armazenados na tabela sales que tem três colunas: date - data da venda do produto region - nome da região products_sold - número de produtos vendidos Aqui está o código necessário para criar esse relatório: SELECT date, region, products_sold, AVG(products_sold) OVER(PARTITION BY date) AS avg_date, AVG(products_sold) OVER(PARTITION BY region) AS avg_region FROM sales ORDER BY region, date; Este código seleciona as colunas date, region, e products_sold. Em seguida, ele calcula o número médio de produtos vendidos em cada data. Isto é definido pela cláusula PARTITION BY(). O resultado será mostrado na coluna avg_date. A linha seguinte também calcula o número médio de produtos vendidos, desta vez em cada região. O resultado será mostrado na coluna avg_region. Em seguida, o resultado é ordenado pela região e a data usando a cláusula ORDER BY. Veja os resultados abaixo: dateregionproducts_soldavg_dateavg_region 2020-03-01Region 19990.33333380 2020-03-02Region 1986980 2020-03-03Region 14347.33333380 2020-03-01Region 29690.33333361.333333 2020-03-02Region 2596961.333333 2020-03-03Region 22947.33333361.333333 2020-03-01Region 37690.33333365.333333 2020-03-02Region 3506965.333333 2020-03-03Region 37047.33333365.333333 Exemplo 3: Cálculo da Soma Cumulativa de Produtos Vendidos por Região A gerência ficou feliz com seu relatório anterior! Agora, eles querem que você calcule a soma acumulada (ou o total em funcionamento) dos produtos vendidos em cada região. As funções de janela são úteis para fazer tais cálculos. O cálculo será realizado sobre a mesa sales usado no Exemplo 2. Este código permitirá que você entregue rapidamente os números necessários: SELECT date, region, products_sold, SUM(products_sold) OVER(PARTITION BY region ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS cumulative_region FROM sales ORDER BY region, date; A primeira parte do código seleciona as mesmas colunas que o código do Exemplo 2. Em seguida, calcula a soma dos produtos por região. Isto é definido pela cláusula PARTITION BY(). Naturalmente, você precisa da soma acumulada, não da soma total. É por isso que a janela é ordenada pela data usando o comando ORDER BY. Agora que tudo está definido, você precisa dizer a SQL para adicionar o valor da linha atual à soma das linhas anteriores dentro da janela. Isto é feito por ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW. A função de janela somará todas as linhas antes da linha atual (é por isso que UNBOUNDED PRECEDING) e nenhuma linha depois da linha atual (é por isso que CURRENT ROW) dentro da janela especificada. O resultado será mostrado na coluna cumulative_region. O resultado será ordenado pela região e pela data, como no exemplo anterior. Após executar o código, você obterá a tabela abaixo: dateregionproducts_soldcumulative_region 2020-03-01Region 19999 2020-03-02Region 198197 2020-03-03Region 143240 2020-03-01Region 29696 2020-03-02Region 259155 2020-03-03Region 229184 2020-03-01Region 37676 2020-03-02Region 350126 2020-03-03Region 370196 Exemplo 4: Compare os preços das ações com os preços mínimo e máximo no mercado Sua empresa está monitorando os preços das ações na NASDAQ e NYSE. A administração quer que você calcule os preços mínimos e máximos das ações em ambos os mercados nos últimos 365 dias. Eles também querem ver como o preço de cada ação negociada em 2020 difere do preço mínimo e máximo no mercado. A tabela stockprice contém dados de 15/03/2019 a 14/03/2020 e consiste nas seguintes colunas: date - data da negociação stock_name - nome do estoque stock_price - preço das ações stock_market - mercado em que as ações estão sendo negociadas max_price - preço máximo no mercado nos últimos 365 dias min_price - preço mínimo no mercado nos últimos 365 dias diff_max - preço das ações menos o preço máximo no mercado nos últimos 365 dias diff_min - preço das ações menos o preço mínimo no mercado nos últimos 365 dias O código que criará rapidamente o relatório solicitado se assemelha a este: SELECT date, stock_name, stock_price, stock_market, MAX(stock_price) OVER(PARTITION BY stock_market) as max_price, MIN(stock_price) OVER(PARTITION BY stock_market) as min_price, stock_price - MAX(stock_price) OVER(PARTITION BY stock_market) AS diff_max, stock_price - MIN(stock_price) OVER(PARTITION BY stock_market) AS diff_min FROM stockprice WHERE date > '2019-12-31' ORDER BY date; A primeira parte do código seleciona as colunas originais na tabela: date, stock_name, stock_price, e stock_market. Em seguida, a função de janela MAX() com a cláusula PARTITION BY calcula o preço máximo para cada mercado, NASDAQ e NYSE, separadamente. O resultado será mostrado na coluna max_price. A próxima linha de código funciona da mesma forma, exceto que agora ele calcula o preço mínimo. O resultado será mostrado na coluna min_price. As seguintes linhas de código calculam a diferença entre o preço da ação e o preço máximo e mínimo, respectivamente, para cada mercado. Os resultados serão mostrados nas colunas diff_max e diff_min. Como o relatório só precisa mostrar dados a partir de 2020, usei a cláusula WHERE. Finalmente, a tabela resultante é ordenada pela data, o que é lógico para tal relatório. Aqui está como são as primeiras várias linhas do relatório: datestock_namestock_pricestock_marketmax_pricemin_pricediff_maxdiff_min 1.1.2020MYOS RENS Technology Inc.91.49NASDAQ99.7530.37-8.2660.39 1.1.2020Huron Consulting Group Inc.59.56NASDAQ99.7530.37-40.1928.46 1.1.2020Sensient Technologies Corporation82.05NYSE99.5430.37-17.4951.68 2.1.2020Regions Financial Corporation46.75NYSE99.5430.37-52.7916.38 2.1.2020Ottawa Bancorp, Inc.51.55NASDAQ99.7530.37-48.220.45 3.1.2020Vanguard Long-Term Government Bond ETF70.62NASDAQ99.7530.37-29.1339.52 3.1.2020Bruker Corporation52.99NASDAQ99.7530.37-46.7621.89 Exemplo 5: Calcular a porcentagem de mudança de preço e as médias móveis A gerência agora sabe que você pode entregar relatórios com grande precisão e rapidez. Eles estão impressionados! Eles não percebem que você tem aprendido as funções da janela SQL e que o que eles pediram é fácil para você. Em seguida, eles pedem algo que deve levar muito mais tempo. Mas não vai demorar! Você tem uma tabela de preços que contém todos os price mudanças de um estoque em 2020. Às vezes há apenas uma mudança diária, às vezes há mais. A tabela é composta pelas seguintes colunas: date - data do preço stock_price - preço das ações A gerência lhe pediu que lhes enviasse um relatório que tomaria cada preço e o compararia com o preço anterior. Além disso, eles pediram que você calcule a média móvel do preço da ação. É assim que você vai fazer: SELECT date, stock_price, (stock_price/LAG(stock_price) OVER(ORDER BY date)) - 1 AS percent_change, AVG(stock_price) OVER(ORDER BY date ROWS BETWEEN 0 PRECEDING AND 4 FOLLOWING) AS moving_avg FROM price; Então, o que este código faz? Primeiro, ele seleciona as colunas originais na tabela: date e stock_price. A próxima linha introduz uma nova função de janela, LAG(). Esta função acessa os dados da linha anterior, o que é ideal para esta tarefa. O stock_price é dividido pelo preço anterior (daí, a função LAG() ). Em seguida, 1 é subtraído do resultado para obter uma porcentagem. O resultado será mostrado na coluna percent_change. A linha seguinte calcula a média móvel. Ela usa a função da janela AVG(), que você já conhece. Na cláusula OVER(), os dados são ordenados pela data. A gerência não especificou como eles querem que a média móvel seja calculada. Portanto, decidi calculá-la usando cinco mudanças de preço, o que está especificado em ROWS BETWEEN 0 PRECEDING AND 4 FOLLOWING. Ao calcular a média móvel, o código levará em conta a linha atual e as quatro linhas que se seguem, que são cinco no total. Você pode jogar com essa parte do código, uma vez que não há um número definido de dados que devem ser levados em conta no cálculo das médias móveis. Depende da quantidade e do tipo de dados, assim como da preferência individual. Ao alterar os números que vêm antes de PRECEDING e FOLLOWING, você pode mudar fácil e rapidamente o cálculo, dependendo da metodologia que você decidir utilizar. Veja os resultados abaixo: datestock_pricepercent_changemoving_avg 1.1.201936.37NULL39.126 1.1.201937.890.041792637.922 1.1.201944.080.163367638.768 2.1.201930.43-0.309664340.84 3.1.201946.860.539927741.058 3.1.201930.35-0.352326143.3 3.1.201942.120.387808845.276 4.1.201954.440.292497648.452 5.1.201931.52-0.42101448.78 6.1.201958.070.842322352.822 7.1.201940.23-0.307215549.19 Você acha que o aprendizado Funções de Janela (Window Functions) em SQL pode ajudá-lo em seu trabalho? Eu dei exemplos comerciais do mundo real como ponto de partida em vez de análise de código de funções de janela pura. Todos os cinco exemplos são algo com que já lidei em minha carreira. Foi assim que eu aprendi SQL. Primeiro, eu tenho um problema para resolver. Depois, tentei descobrir como fazer isso usando SQL. Se você acha que as funções de janela serão úteis para seu trabalho, este curso LearnSQL.com.br é uma ótima maneira de aprender mais. Se você achou estes exemplos interessantes ou quiser compartilhar alguns de seus exemplos do mundo real, sinta-se à vontade para comentar abaixo! Tags: sql aprender sql window functions