OVER, PARTITION BY e ORDER BY
Entenda a anatomia de uma especificação de janela e como as partições reiniciam o cálculo.
OVER, PARTITION BY e ORDER BY é uma aula grátis de Coding Interview Prep no CoddyKit. Esta é a aula 1 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Coding Interview Prep, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Coding Interview Prep inclui 4 aulas no total.
Por que os entrevistadores recorrem às funções de janela
Uma função de janela realiza um cálculo sobre um conjunto de linhas relacionadas à linha atual, sem agrupá-las como faz GROUP BY. Essa única característica explica por que os entrevistadores gostam tanto delas: você mantém todas as linhas detalhadas e ainda obtém uma agregação, uma classificação ou um total acumulado ao lado delas.
- GROUP BY retorna uma linha por grupo.
- Função de janela retorna todas as linhas de entrada, com uma coluna calculada adicional.
Quando um entrevistador diz "mostre cada funcionário e o salário médio do departamento na mesma linha", ele está verificando se você recorre a uma função de janela em vez de uma autojunção.
Anatomia da cláusula OVER
Toda função de janela é seguida por uma cláusula OVER (...). A cláusula tem três partes opcionais, e nomeá-las com precisão impressiona os entrevistadores:
- PARTITION BY — divide as linhas em grupos; a função é reiniciada em cada um deles.
- ORDER BY — ordena as linhas dentro de cada partição (necessário para classificações e totais acumulados).
- quadro — limita quais linhas alimentam o cálculo (
ROWS/RANGE).
Um OVER () vazio trata todo o conjunto de resultados como uma única partição.
SELECT
name,
department,
salary,
AVG(salary) OVER (PARTITION BY department) AS dept_avg
FROM employees;Janela versus agregação: mesma função, resultado diferente
A mesma função de agregação se comporta de maneira diferente quando usada como função de janela. Compare conceitualmente as duas consultas abaixo.
AVG(salary)comGROUP BY departmentretorna uma linha por departamento.AVG(salary) OVER (PARTITION BY department)retorna todos os funcionários, cada um acompanhado pela média do departamento.
Dica para a entrevista: destaque que a versão com janela não exige GROUP BY e não remove as linhas de detalhes duplicadas.
-- Aggregate: collapses
SELECT department, AVG(salary)
FROM employees
GROUP BY department;
-- Window: preserves every row
SELECT department, name, AVG(salary) OVER (PARTITION BY department) AS dept_avg
FROM employees;PARTITION BY: Reiniciando o cálculo
PARTITION BY está para as funções de janela assim como GROUP BY está para as agregações, com a diferença de que não reduz as linhas. Cada valor distinto da partição recebe seu próprio cálculo independente.
No exemplo, a numeração das linhas recomeça em 1 para cada departamento. Sem PARTITION BY, a numeração continuaria por todos os funcionários.
- É possível particionar por uma coluna ou por várias.
- Sem
PARTITION BY, há uma única partição enorme (todo o conjunto).
SELECT
department,
name,
ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS rn
FROM employees;ORDER BY dentro de OVER
O ORDER BY dentro de OVER não é igual ao ORDER BY final da consulta. Ele apenas define a sequência das linhas dentro de cada partição para que a função opere sobre ela.
- As funções de classificação (
ROW_NUMBER,RANK) exigem esse elemento — elas precisam de uma ordem para fazer a classificação. - As funções simples de agregação sobre uma partição não precisam dele, a menos que o objetivo seja obter um cálculo acumulado.
Um erro comum em entrevistas técnicas é confundir o ORDER BY da janela com a ordem de apresentação da saída.
SELECT
name,
hire_date,
ROW_NUMBER() OVER (ORDER BY hire_date) AS seniority_rank
FROM employees
ORDER BY name; -- output order is independent of the window orderCombinando PARTITION BY e ORDER BY
A janela de classificação clássica combina os dois: PARTITION BY agrupa e, em seguida, ORDER BY ordena dentro de cada grupo.
Leia a especificação abaixo assim: «Dentro de cada departamento, ordene os funcionários pelo salário em ordem decrescente e numere-os». A pessoa com o maior salário de cada departamento recebe o número de linha 1.
Essa única especificação é a base dos problemas mais comuns de entrevistas técnicas sobre funções de janela, incluindo o padrão dos N primeiros por grupo.
SELECT
department,
name,
salary,
ROW_NUMBER() OVER (
PARTITION BY department
ORDER BY salary DESC
) AS dept_salary_rank
FROM employees;ORDER BY altera o comportamento da agregação
Este é um ponto sutil que os entrevistadores costumam explorar: adicionar ORDER BY a uma janela de agregação a transforma em um cálculo acumulado, porque um quadro implícito («do início da partição até a linha atual») entra em ação.
SUM(x) OVER (PARTITION BY g)→ o mesmo total do grupo em todas as linhas.SUM(x) OVER (PARTITION BY g ORDER BY d)→ um total acumulado até a linha atual.
Saber que ORDER BY adiciona implicitamente um quadro diferencia candidatos de nível intermediário de candidatos iniciantes.
SELECT
account_id,
txn_date,
amount,
SUM(amount) OVER (
PARTITION BY account_id
ORDER BY txn_date
) AS running_balance
FROM transactions;Onde as funções de janela podem ser usadas
As funções de janela só podem aparecer na lista de SELECT e na cláusula ORDER BY. Elas não são permitidas em WHERE, GROUP BY ou HAVING.
O motivo está relacionado à ordem lógica de execução: as funções de janela são avaliadas depois que WHERE, GROUP BY e HAVING são executados. As linhas já foram escolhidas antes mesmo de a janela analisá-las.
É por isso que filtrar por uma classificação exige uma subconsulta ou uma CTE — um ponto explicado detalhadamente em uma lição posterior.
-- This FAILS: window function in WHERE
-- SELECT name FROM employees
-- WHERE ROW_NUMBER() OVER (ORDER BY salary) = 1;
-- This works: window in SELECT, filter outside
SELECT * FROM (
SELECT name, ROW_NUMBER() OVER (ORDER BY salary DESC) AS rn
FROM employees
) t
WHERE rn = 1;Várias funções de janela em uma consulta
É possível usar várias funções de janela no mesmo SELECT, cada uma com sua própria especificação ou compartilhando uma especificação. O banco de dados as calcula em uma única passagem pelos dados particionados.
Isso é útil em entrevistas técnicas quando é necessário obter juntos uma classificação e a média do departamento. Se duas funções compartilham uma especificação, alguns dialetos permitem nomeá-la com uma cláusula WINDOW para evitar repetição.
SELECT
name,
department,
salary,
ROW_NUMBER() OVER w AS rn,
AVG(salary) OVER (PARTITION BY department) AS dept_avg
FROM employees
WINDOW w AS (PARTITION BY department ORDER BY salary DESC);Exemplo resolvido: salário versus média do departamento
Uma pergunta frequente para analistas é: «Liste cada funcionário com seu salário, a média do departamento e a diferença». Uma expressão de janela faz a parte mais trabalhosa; a aritmética faz o restante.
Observe que não há GROUP BY e que cada linha de funcionário é mantida. O valor de dept_avg se repete para todos no mesmo departamento, exatamente o que torna possível fazer a comparação linha a linha.
SELECT
name,
department,
salary,
AVG(salary) OVER (PARTITION BY department) AS dept_avg,
salary - AVG(salary) OVER (PARTITION BY department) AS diff_from_avg
FROM employees
ORDER BY department, salary DESC;Erros comuns que os entrevistadores observam
Evite estas armadilhas quando surgirem funções de janela:
- Colocar uma função de janela em
WHEREouHAVING— é ilegal; use uma subconsulta. - Esquecer o
ORDER BYem uma função de classificação — os resultados se tornam arbitrários. - Supor que
PARTITION BYreduz a quantidade de linhas — isso nunca acontece. - Confundir o
ORDER BYda janela com a ordem final da saída. - Adicionar
ORDER BYa uma janela de agregação sem perceber que ela se tornou um total acumulado.
Verificação rápida
Teste sua compreensão da especificação da janela.
Recapitulação: a especificação da janela
Agora você domina a estrutura de OVER (...):
- As funções de janela mantêm todas as linhas enquanto calculam valores usando linhas relacionadas.
- PARTITION BY agrupa e reinicia o cálculo; nunca remove linhas.
- ORDER BY ordena as linhas dentro de uma partição; as funções de classificação exigem esse elemento, e ele transforma agregações em cálculos acumulados.
- As funções de janela só são permitidas em
SELECTeORDER BY— nunca emWHERE/HAVING.
Em seguida, você atribuirá números de sequência determinísticos com ROW_NUMBER.
Perguntas Frequentes
A aula “OVER, PARTITION BY e ORDER BY” é grátis?
Sim — o texto completo de “OVER, PARTITION BY e ORDER BY” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Coding Interview Prep, atualize para CoddyKit PRO. O curso de Coding Interview Prep inclui 4 aulas no total.
O que vou aprender em “OVER, PARTITION BY e ORDER BY”?
Entenda a anatomia de uma especificação de janela e como as partições reiniciam o cálculo. Você pratica Coding Interview Prep com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar Coding Interview Prep?
Nenhuma experiência prévia é necessária. Coding Interview Prep no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 1 de 4.
Quanto tempo leva a aula “OVER, PARTITION BY e ORDER BY”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de Coding Interview Prep?
Sim. Cada aula de Coding Interview Prep inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- OVER, PARTITION BY e ORDER BY
- ROW_NUMBER para sequenciamento exclusivo
- RANK versus DENSE_RANK em empates
- Filtrando um resultado de janela