Imagina que tu trabalha como garçom (ou barista, se tu curte café) num restaurante grandão. Todo dia tu faz a soma das gorjetas que ganhou. Mas tem um detalhe: o restaurante é dividido em áreas, e tu quer saber quanto de gorjeta rolou em cada área separada. PARTITION BY é tipo o que o SQL usa pra "dividir o restaurante em áreas".
Falando mais formalmente, PARTITION BY é usado nas funções window pra separar todas as linhas da tabela em grupos (ou "partições"). Dentro de cada grupo, a função window roda de novo. É como se tu aplicasse a função separadamente em cada "partição".
Exemplo: como isso funciona
Vamos supor que a gente tem uma tabela sales com dados de vendas:
| region | salesperson | amount |
|---|---|---|
| North | Alice | 100 |
| North | Bob | 200 |
| South | Alice | 150 |
| South | Charlie | 250 |
Se a gente quiser calcular quanto cada vendedor faturou, mas separado por região, PARTITION BY é o que a gente precisa.
Sintaxe do PARTITION BY
A sintaxe é bem de boa:
funcao_window() OVER (PARTITION BY coluna_ou_colunas)
funcao_window()— tipoSUM(),AVG(),ROW_NUMBER()e por aí vai.PARTITION BY coluna— diz por qual coluna tu vai separar as linhas.OVER()— é o operador que fala pro SQL: "Faz isso dentro da janela que eu tô dizendo".
Exemplo: soma por grupos
Bora calcular o total de vendas pra cada região:
SELECT
region,
salesperson,
amount,
SUM(amount) OVER (PARTITION BY region) AS total_sales_by_region
FROM sales;
O resultado vai ser assim:
| region | salesperson | amount | total_sales_by_region |
|---|---|---|---|
| North | Alice | 100 | 300 |
| North | Bob | 200 | 300 |
| South | Alice | 150 | 400 |
| South | Charlie | 250 | 400 |
O que tá rolando aqui? O SQL separa as linhas em grupos pelo valor da coluna region (North e South), aí aplica a função SUM() separada pra cada grupo. No fim, as linhas do grupo "North" pegam o mesmo valor de soma, e as do grupo "South" outro valor.
Exemplos de uso do PARTITION BY
Bora ver como PARTITION BY pode ser útil em situações da vida real.
Exemplo 1: Ranking dentro do grupo
Imagina que a gente quer ranquear os vendedores dentro de cada região pelo valor das vendas. Pra isso, dá pra usar PARTITION BY junto com a função RANK():
SELECT
region,
salesperson,
amount,
RANK() OVER (PARTITION BY region ORDER BY amount DESC) AS rank_in_region
FROM sales;
Resultado:
| region | salesperson | amount | rank_in_region |
|---|---|---|---|
| North | Bob | 200 | 1 |
| North | Alice | 100 | 2 |
| South | Charlie | 250 | 1 |
| South | Alice | 150 | 2 |
A função RANK() dá um ranking dentro de cada grupo region, começando do 1. Saca que pra cada grupo o ranking começa do um.
Exemplo 2: Comparando cada valor com a média do grupo
Vamos supor que a gente quer ver quanto cada vendedor faturou comparado com a média da região dele. Bora usar AVG():
SELECT
region,
salesperson,
amount,
AVG(amount) OVER (PARTITION BY region) AS avg_sales_by_region,
amount - AVG(amount) OVER (PARTITION BY region) AS diff_from_avg
FROM sales;
Resultado:
| region | salesperson | amount | avg_sales_by_region | diff_from_avg |
|---|---|---|---|---|
| North | Alice | 100 | 150 | -50 |
| North | Bob | 200 | 150 | 50 |
| South | Alice | 150 | 200 | -50 |
| South | Charlie | 250 | 200 | 50 |
Primeiro o SQL separa as linhas em grupos por region. Depois calcula a média AVG(amount) pra cada grupo. Por fim, pra cada linha, calcula a diferença entre o valor dela e a média.
Exemplo 3: Numerando linhas dentro do grupo
Digamos que tu quer numerar todas as transações dentro de cada grupo de região. Bora usar ROW_NUMBER():
SELECT
region,
salesperson,
amount,
ROW_NUMBER() OVER (PARTITION BY region ORDER BY amount DESC) AS row_number
FROM sales;
Resultado:
| region | salesperson | amount | row_number |
|---|---|---|---|
| North | Bob | 200 | 1 |
| North | Alice | 100 | 2 |
| South | Charlie | 250 | 1 |
| South | Alice | 150 | 2 |
Comparando com GROUP BY
Direto rola confusão entre PARTITION BY e GROUP BY. Bora comparar eles:
GROUP BY
GROUP BY muda a estrutura do resultado — ele transforma as linhas da tabela em agregados. Tipo assim:
SELECT
region,
SUM(amount) AS total_sales
FROM sales
GROUP BY region;
Resultado:
| region | total_sales |
|---|---|
| North | 300 |
| South | 400 |
Aqui a gente perde a info dos vendedores, porque os dados são agregados.
PARTITION BY
PARTITION BY, ao contrário, não muda a estrutura. A gente ainda vê cada linha, mas agora tem valores extras calculados por grupo. Ou seja, PARTITION BY deixa tu agregar sem perder os detalhes.
Erros comuns usando PARTITION BY
Erro 1: Esqueceu o PARTITION BY
Às vezes tu quer agrupar os dados, mas esquece de usar o PARTITION BY. Tipo assim:
SELECT
region,
salesperson,
amount,
SUM(amount) OVER () AS total_sales
FROM sales;
Resultado:
| region | salesperson | amount | total_sales |
|---|---|---|---|
| North | Alice | 100 | 700 |
| North | Bob | 200 | 700 |
| South | Alice | 150 | 700 |
| South | Charlie | 250 | 700 |
Aqui o SUM(amount) foi calculado pra tabela toda, não separado por região. Se tu quiser considerar as regiões, não esquece de botar PARTITION BY region.
Erro 2: Ordem errada no ORDER BY
A ordem das linhas dentro da janela é importante pra funções tipo RANK() ou ROW_NUMBER(). Fica ligado quando usar ORDER BY dentro do OVER().
GO TO FULL VERSION