27th Jul 2023 15 minutos de leitura Como usar SUM() com OVER(PARTITION BY) no SQL Martyna Sławińska sql PARTITION BY window functions Índice A cláusula OVER() no SQL Exemplo 1A: Cálculo da soma de cada grupo - SUM() com OVER(PARTITION BY ...) Exemplo 1B: Cálculo do salário para cada cargo Exemplo 2: Calcular a proporção de um valor de uma única linha em relação ao total Exemplo 2: Calcular a proporção de um valor de uma única linha em relação ao total Qual é a diferença entre SUM() com OVER(PARTITION BY …) e usar SUM() com GROUP BY? Exemplo 3: cálculo de um total em execução usando SUM() com OVER(PARTITION BY) Exemplo 4: Contagem de objetos em categorias personalizadas Exemplo 5: Cálculo de um total de pedido com descontos usando SUM() com CASE WHEN Vá em frente e use SUM() com OVER() e PARTITION BY Descubra casos de uso reais da função SUM() com a cláusula OVER(PARTITION BY). Aprenda a sintaxe e confira 5 exemplos diferentes. Usamos as funções de janela do SQL para realizar operações em grupos de dados. Essas operações incluem as funções matemáticas SUM(), COUNT(), AVG(), entre outras. Neste artigo, explicaremos o que SUM() com OVER(PARTITION BY) faz no SQL. Mostraremos os casos de uso mais comuns em aplicativos do mundo real para determinar a proporção entre o valor da linha individual e o valor total, calcular totais em execução e encontrar um total de pedido personalizado que inclua descontos para determinados produtos. Para obter um guia detalhado sobre o uso do site SUM() com OVER() e outras funções de janela, assista ao nosso Funções de Janela (Window Functions) em SQL curso interativo. Ele explica detalhadamente todos os conceitos de função de janela SQL e tem mais de 200 exercícios. Vamos começar. A cláusula OVER() no SQL No SQL, a cláusula OVER() é usada para introduzir funções de janela. A sintaxe geral é: SELECT … <window function> OVER(...) … OVER() informa ao banco de dados que queremos usar funções de janela. A função de janela pode ser uma função agregada, como SUM(), ou outra função de janela. Uma função de janela funciona em um "quadro de janela" ou em um conjunto de linhas relacionadas à linha atual. OVER() define o quadro de janela para cada linha. Uma cláusula OVER() vazia informa ao banco de dados que todo o conjunto de resultados é a moldura da janela. Vamos dar uma olhada em um exemplo da sintaxe SUM() OVER(). Usaremos a tabela employees da tabela de dados de amostra fornecida pelo Oracle Live SQL. Essa tabela consiste nas seguintes colunas: emp_id é o identificador do funcionário. name é o nome do funcionário. job é o título do cargo. dept_id é o identificador do departamento. salary é o salário do funcionário. EMP_IDNAMEJOBDEPT_IDSALARY 7839KINGPRESIDENT105000 7698BLAKEMANAGER302850 … 7900JAMESCLERK30950 7934MILLERCLERK101300 Podemos usar a função SUM() com a cláusula OVER() para obter o salário total de todos os funcionários e exibir o salário total ao lado do salário de cada funcionário. SELECT emp_id, name, job, dept_id, salary, SUM(salary) OVER() AS total_salary FROM employees; emp_idNAMEJOBDEPT_IDSALARYTOTAL_SALARY 7839KINGPRESIDENT10500029025 7698BLAKEMANAGER30285029025 … 7900JAMESCLERK3095029025 7934MILLERCLERK10130029025 A função SUM() é executada para cada linha da tabela. Toda vez que é chamada, ela obtém as informações de salário de todas as linhas da tabela para calcular o valor total do salário. O salário total é exibido ao lado dos detalhes de cada linha individual. Os detalhes das linhas individuais são preservados e exibidos ao lado do salário total. Neste exemplo, a moldura da janela (o conjunto de linhas em que o SUM() está operando) é o conjunto de dados inteiro. Você pode adicionar cláusulas adicionais em OVER() para alterar o quadro da janela. Exemplo 1A: Cálculo da soma de cada grupo - SUM() com OVER(PARTITION BY ...) A cláusula OVER() pode conter detalhes sobre a forma como queremos particionar os dados. Usamos a cláusula PARTITION BY em OVER() para dividir os dados em partições ou grupos. O uso de PARTITION BY é semelhante ao uso de GROUP BY, pois as linhas são particionadas em grupos com base no valor de algumas colunas. Quando usamos o SUM() OVER(PARTITION BY …), podemos calcular a soma dos valores de cada grupo ou partição de dados. Por exemplo, podemos calcular o salário total de cada departamento: SELECT emp_id, name, job, dept_id, salary, SUM(salary) OVER(PARTITION BY dept_id) AS dept_total_salary FROM employees; Aqui está o resultado: EMP_IDNAMEJOBDEPT_IDSALARYDEPT_TOTAL_SALARY 7782CLARKMANAGER1024508750 7934MILLERCLERK1013008750 7839KINGPRESIDENT1050008750 7902FORDANALYST20300010875 7788SCOTTANALYST20300010875 7566JONESMANAGER20297510875 7369SMITHCLERK2080010875 7876ADAMSCLERK20110010875 7521WARDSALESMAN3012509400 7654MARTINSALESMAN3012509400 7844TURNERSALESMAN3015009400 7900JAMESCLERK309509400 7499ALLENSALESMAN3016009400 7698BLAKEMANAGER3028509400 Usamos SUM(salary) OVER(PARTITION BY dept_id) para obter o salário total por departamento. A cláusula PARTITION BY divide as linhas em grupos com base na coluna dept_id. As linhas com dept_id igual a 10 são colocadas em um grupo (marcado em amarelo na tabela acima), as linhas com dept_id igual a 20 são colocadas em outro grupo (marcado em verde) e, finalmente, as linhas com dept_id igual a 30 são colocadas em outro grupo (marcado em vermelho). A função SUM() calcula a soma das linhas em cada grupo. Observe que, ao usar SUM() OVER(PARTITION BY), você mantém os detalhes das linhas individuais. Você pode, por exemplo, ver os detalhes do funcionário chamado Ford: seu cargo, seu salário e como ele se compara ao total de salários em seu departamento. Esse é o uso mais comum do site SUM() OVER(PARTITION BY): você calcula o valor da soma para cada grupo de dados e mantém os detalhes das linhas individuais. Vejamos um exemplo semelhante. Exemplo 1B: Cálculo do salário para cada cargo Podemos usar SUM(salary) OVER(PARTITION BY job) para obter o salário total por cargo. Vamos dar uma olhada: SELECT emp_id, name, job, dept_id, salary, SUM(salary) OVER(PARTITION BY job) AS job_total_salary FROM employees; Aqui está o resultado: EMP_IDNAMEJOBDEPT_IDSALARYJOB_TOTAL_SALARY 7782CLARKMANAGER1024508275 7698BLAKEMANAGER3028508275 7566JONESMANAGER2029758275 7934MILLERCLERK1013004150 7369SMITHCLERK208004150 7876ADAMSCLERK2011004150 7900JAMESCLERK309504150 7902FORDANALYST2030006000 7788SCOTTANALYST2030006000 7521WARDSALESMAN3012505600 7654MARTINSALESMAN3012505600 7844TURNERSALESMAN3015005600 7499ALLENSALESMAN3016005600 7839KINGPRESIDENT1050005000 Desta vez, as linhas são agrupadas com base no valor do cargo e não no ID do departamento. Os funcionários com o mesmo cargo são colocados em um grupo e calculamos o salário total das pessoas com esse cargo. A função SUM() é aplicada a todos os salários em cada grupo: o salário total do grupo "Manager" é a soma de 2450, 2850 e 2975, que são os salários dos três gerentes que estão em nossa tabela. Exemplo 2: Calcular a proporção de um valor de uma única linha em relação ao total Normalmente, queremos ver a comparação entre cada linha individual e a soma total. Vamos calcular a porcentagem de cada salário individual em relação ao total de salários em seu departamento. SELECT emp_id, name, job, dept_id, salary, ROUND(100.0 * salary / SUM(salary) OVER(PARTITION BY dept_id), 2) AS percentage_of_dept_total_salary FROM employees; EMP_IDNAMEJOBDEPT_IDSALARYPERCENTAGE_OF_DEPT_TOTAL_SALARY 7782CLARKMANAGER10245028 7934MILLERCLERK10130014.86 7839KINGPRESIDENT10500057.14 7902FORDANALYST20300027.59 7788SCOTTANALYST20300027.59 7566JONESMANAGER20297527.36 7369SMITHCLERK208007.36 7876ADAMSCLERK20110010.11 7521WARDSALESMAN30125013.3 7654MARTINSALESMAN30125013.3 7844TURNERSALESMAN30150015.96 7900JAMESCLERK3095010.11 7499ALLENSALESMAN30160017.02 7698BLAKEMANAGER30285030.32 Desta vez, as linhas são agrupadas com base no valor job em vez do ID do departamento. Os funcionários com o mesmo cargo são colocados em um grupo e calculamos o salário total das pessoas nesse cargo. A função SUM() é aplicada a todos os salários em cada grupo: o salário total do grupo "Manager" é a soma de 2450, 2850 e 2975, que são os salários dos três gerentes que estão em nossa tabela. Exemplo 2: Calcular a proporção de um valor de uma única linha em relação ao total Normalmente, queremos ver a comparação entre cada linha individual e a soma total. Vamos calcular a porcentagem de cada salário individual em relação ao total de salários em seu departamento. SELECT emp_id, name, job, dept_id, salary, ROUND(100.0 * salary / SUM(salary) OVER(PARTITION BY dept_id), 2) AS percentage_of_dept_total_salary FROM employees; EMP_IDNAMEJOBDEPT_IDSALARYPERCENTAGE_OF_DEPT_TOTAL_SALARY 7782CLARKMANAGER10245028 7934MILLERCLERK10130014.86 7839KINGPRESIDENT10500057.14 7902FORDANALYST20300027.59 7788SCOTTANALYST20300027.59 7566JONESMANAGER20297527.36 7369SMITHCLERK208007.36 7876ADAMSCLERK20110010.11 7521WARDSALESMAN30125013.3 7654MARTINSALESMAN30125013.3 7844TURNERSALESMAN30150015.96 7900JAMESCLERK3095010.11 7499ALLENSALESMAN30160017.02 7698BLAKEMANAGER30285030.32 Podemos ver, por exemplo, que o analista Scott tem um salário individual de 3.000; isso representa 27,59% do total de salários em seu departamento. Aqui está um detalhamento das funções usadas para realizar essa tarefa: Pegamos cada salário individual e o dividimos pelo salário total do departamento: salary / SUM(salary) OVER(PARTITION BY dept_id) Para obter uma porcentagem, multiplicamos por 100%: 0 * salary / SUM(salary) OVER(PARTITION BY dept_id) Em seguida, usamos a função ROUND() para obter dois dígitos decimais: ROUND(100.0 * salary / SUM(salary) OVER(PARTITION BY dept_id), 2) O cálculo da proporção entre a linha individual e a soma de um grupo é outro caso de uso muito comum de SUM() com OVER(PARTITION BY). De maneira semelhante, você poderia calcular a diferença entre o total do grupo e a linha individual. Qual é a diferença entre SUM() com OVER(PARTITION BY …) e usar SUM() com GROUP BY? A cláusula PARTITION BY realiza uma tarefa semelhante à da cláusula GROUP BY. Tanto OVER(PARTITION BY) quanto GROUP BY dividem o conjunto de dados em partições ou grupos. Ao usar a função SUM(), ambas as expressões calculam a soma de cada grupo. Então, qual delas você deve escolher? Ao usar GROUP BY, os detalhes de linhas individuais são recolhidos. Dê uma olhada: SELECT job, SUM(salary) AS total_salary FROM employees GROUP BY job; JOBTOTAL_SALARY ANALYST6000 CLERK4150 SALESMAN5600 MANAGER8275 PRESIDENT5000 Aqui, obtemos o valor total do salário para cada cargo sem considerar os salários individuais dos funcionários. No entanto, se você quiser comparar o valor da soma total com os valores das linhas individuais (por exemplo, para calcular a proporção entre o valor individual e o total), o caminho a seguir é OVER(PARTITION BY …). Ele retorna todas as linhas individuais juntamente com o valor da soma total de cada linha. Esse valor de soma total pode ser diferente, dependendo da partição à qual a linha pertence. SELECT name, job, salary, SUM(salary) OVER(PARTITION BY job) AS total_salary FROM employees; NAMEJOBSALARYTOTAL_SALARY FORDANALYST30006000 SCOTTANALYST30006000 SMITHCLERK8004150 JAMESCLERK9504150 ADAMSCLERK11004150 MILLERCLERK13004150 BLAKEMANAGER28508275 JONESMANAGER29758275 CLARKMANAGER24508275 KINGPRESIDENT50005000 TURNERSALESMAN15005600 ALLENSALESMAN16005600 WARDSALESMAN12505600 MARTINSALESMAN12505600 O valor total_salary corresponde aos resultados da consulta anterior com GROUP BY. Mas aqui, você também pode ver os salários individuais. Por exemplo, há dois analistas que ganham 6.000 no total; cada um deles ganha 3.000. A regra geral é: se você quiser saber apenas o valor da soma de cada grupo e não estiver interessado nos detalhes de cada linha individual, deverá usar a cláusula GROUP BY. Se você estiver interessado tanto na soma de cada grupo quanto nos detalhes de cada linha individual, use SUM() OVER(PARTITION BY). Exemplo 3: cálculo de um total em execução usando SUM() com OVER(PARTITION BY) Outro uso comum da sintaxe SUM() OVER(...) é calcular o total em execução. Um total em execução é a soma cumulativa dos números anteriores em uma coluna. Usamos totais em execução para calcular valores que se acumulam ao longo do tempo. Por exemplo, com um total em execução, você pode calcular o uso mensal de dados móveis adicionando o valor de cada dia subsequente à soma dos valores dos dias anteriores. Da mesma forma, é possível calcular como o número de usuários registrados aumenta a cada dia ou como a receita total aumenta a cada transação. Usamos a sintaxe SUM() com OVER(PARTITION BY … ORDER BY …) para calcular o total em execução. Vamos dar uma olhada em um exemplo. Usaremos a tabela orders de dados de amostra fornecidos pelo Oracle Live SQL. Essa tabela armazena dados históricos de pedidos. Cada pedido tem sua data (order_date), representante de vendas (sales_rep_id) e valor total (order_total). Aqui, calculamos o valor total em execução para cada representante de vendas: SELECT order_date, sales_rep_id, order_total, SUM(order_total) OVER(PARTITION BY sales_rep_id ORDER BY order_date) AS running_total FROM orders; ORDER_DATESALES_REP_IDORDER_TOTALRUNNING_TOTAL 29-MAR-07 02.22.40.536996 PM15310794.610794.6 16-AUG-07 03.34.12.234359 PM15378279.689074.2 04-OCT-07 09.53.34.362632 PM15312989203.2 21-NOV-07 10.22.33.263332 AM15313824103027.2 16-DEC-07 08.19.55.462332 PM15311188.5114215.7 27-JUL-06 12.22.59.662632 PM15452471.952471.9 27-JUL-06 01.34.16.562632 PM154364656117.9 29-JUN-07 09.53.41.984501 AM1544856165.9 01-JUL-07 04.49.13.615512 PM15422056385.9 02-JUL-07 03.34.44.665170 AM15460056985.9 01-SEP-07 09.53.26.934626 AM154545162436.9 02-OCT-07 05.49.34.678340 PM1546653.469090.3 10-NOV-07 03.49.25.526321 AM15450125119215.3 19-NOV-07 02.41.54.696211 PM15442283.2161498.5 17-DEC-07 05.03.52.562632 PM15410474.6171973.1 Para isso, particionamos nossa tabela por representante de vendas e, em seguida, ordenamos cada partição por data: SUM(order_total) OVER(PARTITION BY sales_rep_id ORDER BY order_date) O novo elemento de sintaxe aqui é ORDER BY. Ele define como as linhas são classificadas em cada quadro de janela. A função SUM() é aplicada a cada linha; ela soma o valor atual order_total ao valor anterior running_total; os totais em execução são calculados separadamente para cada partição (aqui, para cada ID de representante de vendas). Vamos dar uma olhada mais de perto no representante de vendas com ID 153. Seu primeiro pedido foi feito em29 de março e tinha um valor total de 1.794,6. Nesse momento, o total em execução (a soma) é igual ao valor do pedido. Seu segundo pedido foi em16 de agosto, no valor de 78279,6; agora o total em execução é igual à soma dos valores do primeiro e do segundo pedidos (10794,6 + 78279,6 = 89074,2). Após o terceiro pedido, o total em execução é igual ao total em execução anterior mais o valor do terceiro pedido (89074,2 + 129 = 89203,2). Esse processo é semelhante para o representante de vendas com o ID 154. O cálculo de um total em execução é um padrão comum ao usar o SQL para análise de dados. Você pode ler como calcular um total em execução no SQL em outra parte do nosso blog. Exemplo 4: Contagem de objetos em categorias personalizadas A função SUM() é frequentemente combinada com a instrução CASE WHEN para contar objetos em categorias personalizadas. Por exemplo, talvez você queira computar o salário total dos funcionários em cargos de gerência em um departamento e exibi-lo ao lado dos detalhes de cada funcionário. Você pode fazer isso usando SUM() OVER(PARTITION BY) em combinação com CASE WHEN. Vamos primeiro analisar a instrução CASE WHEN. Ela é semelhante à instrução if, comum em muitas linguagens de programação. Nós a usamos para definir o valor de uma expressão em diferentes situações ou casos. No exemplo a seguir, usamos a instrução CASE WHEN para identificar cada funcionário como gerência (gerentes e presidentes) ou como funcionário comum (todos os outros cargos). Dê uma olhada: SELECT emp_id, name, job, dept_id, CASE WHEN job IN (‘PRESIDENT’, ‘MANAGER’) THEN ‘MANAGEMENT’ ELSE ‘REGULAR’ END AS emp_type salary FROM employees; O comando CASE avalia todas as condições do WHEN. Se encontrar a condição correspondente, retorna o valor no ramo THEN. Se não encontrar a condição correspondente, ele retornará o valor fornecido após ELSE. Em nosso exemplo, os funcionários no cargo de presidente ou gerente são rotulados como 'Management'. Todos os outros cargos recebem o rótulo "Regular". Aqui está o resultado da consulta: EMP_IDNAMEJOBDEPT_IDEMP_TYPESALARY 7782CLARKMANAGER10MANAGEMENT2450 7934MILLERCLERK10REGULAR1300 7839KINGPRESIDENT10MANAGEMENT5000 7902FORDANALYST20REGULAR3000 7788SCOTTANALYST20REGULAR3000 7566JONESMANAGER20MANAGEMENT2975 7369SMITHCLERK20REGULAR800 7876ADAMSCLERK20REGULAR1100 7521WARDSALESMAN30REGULAR1250 7654MARTINSALESMAN30REGULAR1250 7844TURNERSALESMAN30REGULAR1500 7900JAMESCLERK30REGULAR950 7499ALLENSALESMAN30REGULAR1600 7698BLAKEMANAGER30MANAGEMENT2850 Você pode ler mais sobre CASE em nosso artigo Como utilizar o CASO em SQL. Você também pode usar a instrução CASE com SUM() para somar valores em categorias personalizadas. Aqui está a consulta: SELECT dept_id, SUM( CASE WHEN job IN (‘PRESIDENT’, ‘MANAGER’) THEN salary ELSE 0 END) AS dept_management_salary, SUM( CASE WHEN job IN (‘PRESIDENT’, ‘MANAGER’) THEN 0 ELSE salary END) AS dept_regular_salary FROM employees GROUP BY dept_id; DEPT_IDDEPT_MANAGEMENT_SALARYDEPT_REGULAR_SALARY 1074501300 2029757900 3028506550 Para funcionários em cargos de gerência, a primeira instrução CASE retorna o valor da coluna salary. A função SUM(), combinada com GROUP BY, soma todos os salários dos funcionários de gerência com o mesmo dept_id. Dessa forma, calculamos o salário total de gerência por departamento. A segunda instrução CASE calcula o salário total do departamento para todos os funcionários regulares. Você pode calcular o salário total dos funcionários em posição de gerência em um departamento e exibi-lo ao lado dos detalhes do funcionário usando SUM() com PARTITION BY: SELECT emp_id, name, job, dept_id, CASE WHEN job IN (‘PRESIDENT’, ‘MANAGER’) THEN ‘MANAGEMENT’ ELSE ‘REGULAR’ END AS emp_type salary, SUM( CASE WHEN job IN (‘PRESIDENT’, ‘MANAGER’) THEN salary ELSE 0 END) OVER(PARTITION BY dept_id) AS dept_management_salary FROM employees; EMP_IDNAMEJOBDEPT_IDEMP_TYPESALARYDEPT_MANAGEMENT_SALARY 7782CLARKMANAGER10MANAGEMENT24507450 7934MILLERCLERK10REGULAR13007450 7839KINGPRESIDENT10MANAGEMENT50007450 7902FORDANALYST20REGULAR30002975 7788SCOTTANALYST20REGULAR30002975 7566JONESMANAGER20MANAGEMENT29752975 7369SMITHCLERK20REGULAR8002975 7876ADAMSCLERK20REGULAR11002975 7521WARDSALESMAN30REGULAR12502850 7654MARTINSALESMAN30REGULAR12502850 7844TURNERSALESMAN30REGULAR15002850 7900JAMESCLERK30REGULAR9502850 7499ALLENSALESMAN30REGULAR16002850 7698BLAKEMANAGER30MANAGEMENT28502850 As linhas são divididas em grupos com base na coluna dept_id. Há três grupos, um para cada departamento. A função SUM() é aplicada à expressão CASE WHEN. Em vez de calcular o salário total em cada departamento, calculamos o salário total dos funcionários em cargos de gerência no departamento. O CASE retorna 0 para os funcionários regulares (a soma não é aumentada) e o valor do salário para os funcionários gerenciais. Você pode usar esse padrão em muitas situações diferentes. De fato, na próxima seção, veremos outro exemplo de combinação de CASE WHEN com SUM() e OVER(PARTITION BY). Exemplo 5: Cálculo de um total de pedido com descontos usando SUM() com CASE WHEN Neste exemplo, queremos calcular o valor total de cada pedido, incluindo descontos para alguns itens do pedido. Usaremos a sintaxe SUM() OVER(PARTITION BY …) para somar todos os valores de itens por pedido. E para incorporar os descontos do produto, usaremos a instrução CASE WHEN. Usamos a tabela order_items de dados de amostra fornecidos pelo Oracle Live SQL. Essa tabela armazena todos os itens do pedido (product_id) pertencentes a cada pedido (order_id). Ela contém informações sobre o preço unitário do produto (unit_price) e a quantidade do pedido (quantity). Agora, queremos calcular os valores do pedido: um para cada produto do pedido e um total para o pedido; o total do pedido deve incluir quaisquer descontos aplicados aos produtos. O total do pedido é igual ao preço unitário multiplicado pela quantidade do pedido. Entretanto, quando houver um desconto aplicado a um produto, usaremos um demonstrativo CASE WHEN para contabilizá-lo. SELECT order_id, product_id, unit_price, quantity, SUM(CASE -- 20% discount for this product WHEN product_id = 3143 THEN unit_price*quantity*0.8 -- 40% discount for this product WHEN product_id = 3106 THEN unit_price*quantity*0.6 ELSE unit_price*quantity END) OVER(PARTITION BY order_id, product_id) AS order_product_total_with_discount, SUM(CASE -- 20% discount for this product WHEN product_id = 3143 THEN unit_price*quantity*0.8 -- 40% discount for this product WHEN product_id = 3106 THEN unit_price*quantity*0.6 ELSE unit_price*quantity END) OVER(PARTITION BY order_id) AS order_total_with_discount FROM order_items; ORDER_IDPRODUCT_IDUNIT_PRICEQUANTITYORDER_PRODUCT_TOTAL_WITH_DISCOUNTORDER_TOTAL_WITH_DISCOUNT 2354310648611756.844916.2 2354311496.8434162.444916.2 235431237947371344916.2 235431294147192744916.2 235431392148100844916.2 235431431653678.444916.2 23543150175898644916.2 235431633061183044916.2 235431653764236844916.2 235431675168346844916.2 23543170145.2701016444916.2 23543176113.3728157.644916.2 235431826177469744916.2 2355228946200920094513.5 23552308571851054594513.5 2355231186.918816337.294513.5 2355232219188357294513.5 2355232317190323094513.5 235523261.1192211.294513.5 235523301.1197216.794513.5 2355233925199497594513.5 23552359226.620446226.494513.5 Para calcular o total por produto em um pedido, usamos a seguinte sintaxe: SUM(CASE WHEN product_id=3143 THEN unit_price*quantity*0.8 -- 20% discount WHEN product_id=3106 THEN unit_price*quantity*0.6 -- 40% discount ELSE unit_price*quantity END) OVER(PARTITION BY order_id, product_id) AS order_product_total_with_discount Passamos a instrução CASE WHEN como um argumento para a função SUM(); se o ID do produto da linha atual for 3143, aplicaremos um desconto de 20%; para o ID do produto 3106, o desconto será de 40%. Em seguida, particionamos o conjunto de dados por ID do pedido e ID do produto para obter os valores totais de cada produto em um pedido. Observe que usamos duas cláusulas PARTITION BY diferentes na consulta. Para calcular o valor total do produto, particionamos o conjunto de dados por ID do pedido e ID do produto. Para calcular o total por pedido, particionamos o conjunto de dados somente pelo ID do pedido. O valor total do pedido é igual para todas as linhas com o mesmo ID de pedido. Ou seja, se você somar todos os valores totais do produto de um determinado pedido, obterá o valor total do pedido. Por exemplo, para o ID do pedido de 2355, obtemos o seguinte: 9200 + 10545 + 16337.2 + 3572 + 3230 + 211.2 + 216.7 + 4975 + 46226.4 = 94513.5. Aqui estão alguns exemplos da função SUM() com CASE WHEN. Vá em frente e use SUM() com OVER() e PARTITION BY Agora que você já sabe como usar a função de janela SUM() e suas várias opções de sintaxe, pode experimentá-la você mesmo. Apresentamos exemplos de como calcular uma porcentagem de um valor de uma única linha em relação ao total da partição e mostramos como calcular o total em execução e o total personalizado da ordem. Recomendamos que você pratique com seus próprios dados. Para saber mais, experimente nosso curso interativo Funções de Janela (Window Functions) em SQL curso interativo, que explica detalhadamente todos os conceitos das funções de janela. Ou confira nossa Folha de dicas Funções de Janela (Window Functions) em SQL se você quiser uma referência rápida e fácil sobre as funções de janela do SQL. Boa sorte! Tags: sql PARTITION BY window functions