OVER() é uma instrução que diz pro SQL sobre qual conjunto de linhas a função window deve ser aplicada. Dá pra dizer que é um jeito de definir a "janela" de dados pra usar a função window. Imagina que a gente tem uma sala cheia de pessoas e quer contar quantas pessoas estão em cada metro quadrado do chão. O OVER() vai mostrar em qual parte da sala a gente vai focar. Em outras palavras, ele define sobre qual conjunto de linhas a função vai trabalhar.
O operador OVER() é usado só com funções window pra fazer operações sobre linhas de uma ou mais tabelas, sem agrupar os dados.
Sintaxe:
funcao_window() OVER (
[PARTITION BY ...]
[ORDER BY ...]
[ROWS/RANGE ...]
)
Onde:
PARTITION BY— divide o conjunto de dados em grupos lógicosORDER BY— define a ordem das linhas dentro de cada grupoROWS/RANGE— especifica o tamanho da "janela" (tipo, linha atual + 1 próxima)
Exemplo: OVER() sem parâmetros
Quando OVER() é usado sem parâmetros extras, isso quer dizer que a função antes dele vai rodar sobre todo o conjunto de dados.
SELECT
employee_id,
salary,
ROW_NUMBER() OVER () AS row_num -- ROW_NUMBER() vai ser aplicada pra todas as linhas do resultado
FROM employees;
O que rola aqui?
ROW_NUMBER()dá um número único pra cada linha.- Como não tem parâmetro no
OVER(), todas as linhas da tabelaemployeessão tratadas como um bloco só.
Resultado:
| employee_id | salary | row_num |
|---|---|---|
| 1 | 50000 | 1 |
| 2 | 60000 | 2 |
| 3 | 55000 | 3 |
Usando PARTITION BY pra definir grupos
Show, agora imagina que a gente quer numerar os funcionários não na empresa toda, mas dentro de cada departamento. É aí que entra o PARTITION BY.
PARTITION BY dentro do OVER() divide os dados em grupos (ou "partições"). Pra cada grupo, a função calcula o valor separado. Tipo, se o ROW_NUMBER() fosse um garçom, ele começaria a contar de novo pra cada "mesa" (partição).
Exemplo: usando PARTITION BY
SELECT
department_id,
employee_id,
salary,
ROW_NUMBER() OVER (PARTITION BY department_id) AS row_num
FROM employees;
O que rola aqui?
- Os dados da tabela
employeessão divididos em grupos pelo valor dedepartment_id. - Em cada grupo, as linhas recebem um número de ordem pelo
ROW_NUMBER().
Resultado:
| department_id | employee_id | salary | row_num |
|---|---|---|---|
| 1 | 1 | 50000 | 1 |
| 1 | 3 | 55000 | 2 |
| 2 | 2 | 60000 | 1 |
Usando ORDER BY pra definir a ordem
Agora bora colocar um pouco de ordem na parada. Imagina que a gente quer numerar as linhas, mas começando pelo maior salário. Isso dá pra fazer com o ORDER BY.
ORDER BY define a ordem em que as linhas vão ser processadas pela função window.
Exemplo: usando ORDER BY dentro do OVER()
SELECT
department_id,
employee_id,
salary,
RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) AS rank
FROM employees;
O que rola aqui?
- Os dados são divididos em grupos (
PARTITION BY department_id). - Dentro de cada grupo, as linhas são ordenadas do maior pro menor salário (
ORDER BY salary DESC). - Cada linha recebe um rank de acordo com a ordem.
Resultado:
| department_id | employee_id | salary | rank |
|---|---|---|---|
| 1 | 3 | 55000 | 1 |
| 1 | 1 | 50000 | 2 |
| 2 | 2 | 60000 | 1 |
Combinando funções window
SQL deixa usar várias funções window numa mesma query, e cada uma pode rodar com suas próprias regras. É tipo numa sala onde tá rolando música e alguém tá contando pessoas ao mesmo tempo — cada coisa é independente!
Exemplo: várias funções window
SELECT
department_id,
employee_id,
salary,
ROW_NUMBER() OVER (PARTITION BY department_id ORDER BY salary DESC) AS row_num,
AVG(salary) OVER (PARTITION BY department_id) AS avg_salary
FROM employees;
O que rola aqui?
ROW_NUMBER()numera as linhas em cada grupo do maior pro menor salário.AVG()calcula o salário médio em cada grupo.
Resultado:
| department_id | employee_id | salary | row_num | avg_salary |
|---|---|---|---|---|
| 1 | 3 | 55000 | 1 | 52500 |
| 1 | 1 | 50000 | 2 | 52500 |
| 2 | 2 | 60000 | 1 | 60000 |
Exemplos do mundo real
Funções window com OVER() são usadas em vários cenários reais. Olha só alguns exemplos:
- Análise de vendas: ranquear produtos pelo número de vendas em cada categoria.
- Rankings: descobrir a posição dos alunos em cada turma pela média de notas.
- Séries temporais: soma acumulada de vendas ao longo do tempo.
Exemplo de análise de vendas:
SELECT
category_id,
product_id,
product_name,
SUM(sales) OVER (PARTITION BY category_id ORDER BY sales DESC) AS cumulative_sales
FROM products;
Erros comuns ao usar funções window
- Faltou o
PARTITION BY
Se você não usar o PARTITION BY, a função window vai rodar na tabela toda. Isso pode dar resultado estranho, principalmente se você esperava dividir por grupos.
💡 Confere se você deixou claro como a tabela deve ser dividida — tipo por usuário, pedido ou categoria.
- Tipos de dados errados no
ORDER BY
ORDER BY dentro da função window liga muito pra tipo de dado. Se você ordenar por um campo de data que tá como texto (VARCHAR), a ordem pode sair alfabética, não cronológica.
💡 Converte esses campos pro tipo certo (DATE, INTEGER etc) antes de ordenar.
- Uso errado do
ROWS BETWEEN
Por padrão, funções window trabalham com limites definidos pelo ROWS BETWEEN. Se você não definir o limite, pode ser que o RANGE seja usado, e ele pode trazer mais linhas do que você queria.
💡 Pra controlar direitinho, usa ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW se quiser um acumulado do começo até a linha atual.
- Trabalhando errado com
NULL
Funções window podem tratar NULL de jeitos diferentes. Por exemplo, RANK() e DENSE_RANK() vão considerar NULL como valor e dar um rank separado pra ele.
💡 Usa NULLS LAST ou NULLS FIRST no ORDER BY se for importante onde o NULL deve ficar.
- Usar funções window agregadas quando não precisa
Às vezes a galera usa funções window agregadas (SUM() OVER(...)) quando dava pra usar agregação normal com GROUP BY, o que deixa a query mais pesada e lenta.
💡 Só usa funções window quando você realmente precisa manter o detalhe linha a linha.
GO TO FULL VERSION