Mantendo a linha mais recente por chave
Use o padrão de registro mais recente por cliente, particionando pela chave e ordenando pela data.
Mantendo a linha mais recente por chave é uma aula grátis de Coding Interview Prep no CoddyKit. Esta é a aula 4 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.
A questão do registro mais recente por chave
"Retorne o pedido mais recente de cada cliente." "Obtenha o estado mais recente de cada dispositivo." Esse problema de registro mais recente por chave é uma das tarefas de entrevista de SQL mais frequentes, pois aparece constantemente no trabalho real de análise de dados.
Trata-se de um caso especializado de primeiro registro por grupo: particione pela chave, ordene pelo carimbo de data/hora em ordem decrescente e mantenha a primeira linha. Esta lição aprofunda o padrão e suas alternativas.
Por que MAX sozinho não é suficiente
Uma resposta inicial tentadora é MAX(order_date) agrupado por cliente. Isso fornece a data mais recente, mas não o restante da linha desse pedido, o identificador do pedido, o valor ou o estado.
Se o entrevistador quiser a linha completa mais recente, MAX com GROUP BY precisa de uma junção adicional de volta à tabela pela chave e pela data máxima, o que é verboso e pode falhar em caso de empate. As funções de janela são mais simples.
-- Gives the date, not the full row
SELECT customer_id, MAX(order_date) AS last_order
FROM orders
GROUP BY customer_id;O padrão ROW_NUMBER
Particione pela chave, ordene pelo carimbo de data/hora em ordem decrescente, e a linha mais recente receberá rn = 1. Mantenha apenas essas linhas e você terá o registro completo mais recente por chave.
Esta é a resposta padrão. Ela retorna exatamente uma linha por chave mesmo quando os carimbos de data/hora empatam, o que geralmente está implícito em "a linha mais recente".
WITH ranked AS (
SELECT *,
ROW_NUMBER() OVER (
PARTITION BY customer_id
ORDER BY order_date DESC
) AS rn
FROM orders
)
SELECT customer_id, order_id, order_date, amount
FROM ranked
WHERE rn = 1;Tratando empates de carimbo de data/hora
Dois pedidos do mesmo cliente podem compartilhar um order_date (o mesmo dia ou carimbos de data/hora idênticos). Sem um critério de desempate, qual deles se torna rn = 1 é arbitrário e pode mudar entre execuções.
Adicione uma chave secundária única, como order_id DESC, para que a linha mais recente seja determinada de forma inequívoca. Os entrevistadores verificam especificamente se você percebeu esse caso-limite.
ROW_NUMBER() OVER (
PARTITION BY customer_id
ORDER BY order_date DESC, order_id DESC
) AS rnMais recente versus todos os empates
Decida o que "mais recente" significa quando os carimbos de data/hora empatam:
- Se quiser exatamente uma linha por chave → use
ROW_NUMBERcom um critério de desempate. - Se quiser todas as linhas que compartilham o carimbo de data/hora máximo → use
RANK() = 1, que retorna todas as linhas mais recentes empatadas.
Fazer essa pergunta de esclarecimento demonstra que você entende a semântica, não apenas a sintaxe.
WITH ranked AS (
SELECT *,
RANK() OVER (
PARTITION BY customer_id ORDER BY order_date DESC
) AS rnk
FROM orders
)
SELECT * FROM ranked WHERE rnk = 1;A alternativa da subconsulta correlacionada
Antes que as funções de janela fossem universais, a resposta para o registro mais recente por chave usava uma subconsulta correlacionada: mantenha uma linha apenas se nenhuma outra linha da mesma chave tiver uma data maior.
Ela funciona, mas executa a consulta interna para cada linha, portanto é mais lenta em tabelas grandes e complicada em caso de empate. Mencione-a para demonstrar conhecimento das alternativas, mas prefira a resposta com função de janela por motivos de desempenho.
SELECT o.*
FROM orders o
WHERE o.order_date = (
SELECT MAX(o2.order_date)
FROM orders o2
WHERE o2.customer_id = o.customer_id
);Atalho DISTINCT ON do PostgreSQL
O PostgreSQL oferece uma forma concisa: DISTINCT ON (key) mantém a primeira linha de cada chave de acordo com a ORDER BY. A ORDER BY deve começar pelas mesmas colunas da chave e, em seguida, pelo critério de desempate e pelo carimbo de data/hora.
É elegante e rápido no PostgreSQL, mas não é portável. Cite-o como um recurso adicional específico do dialeto, mantendo ROW_NUMBER como padrão portável.
SELECT DISTINCT ON (customer_id)
customer_id, order_id, order_date, amount
FROM orders
ORDER BY customer_id, order_date DESC, order_id DESC;Registro mais recente com uma condição
Perguntas reais adicionam filtros: "o pedido concluído mais recente por cliente". Aplique o filtro antes da classificação para que apenas as linhas qualificadas sejam numeradas.
Coloque a condição no WHERE da consulta interna (ela é executada antes da função de janela) e depois selecione rn = 1 na consulta externa. Filtrar depois da classificação retornaria a linha errada.
WITH ranked AS (
SELECT *,
ROW_NUMBER() OVER (
PARTITION BY customer_id ORDER BY order_date DESC, order_id DESC
) AS rn
FROM orders
WHERE status = 'completed'
)
SELECT * FROM ranked WHERE rn = 1;Exemplo resolvido: estado mais recente do dispositivo
Uma tabela status_log registra device_id, status e logged_at. Para obter o estado atual de cada dispositivo, particione por device_id, ordene por logged_at DESC e mantenha rn = 1.
Esse é o mecanismo por trás de painéis que mostram o "estado atual" de muitas entidades a partir de um registro de eventos somente para inclusão. A mesma receita permite consultas de preço mais recente, localização mais recente e versão mais recente.
WITH latest AS (
SELECT device_id, status, logged_at,
ROW_NUMBER() OVER (
PARTITION BY device_id ORDER BY logged_at DESC
) AS rn
FROM status_log
)
SELECT device_id, status, logged_at
FROM latest
WHERE rn = 1;Observações de desempenho
Pontos que demonstram senioridade:
- Um índice em
(customer_id, order_date DESC)permite que o mecanismo leia a linha mais recente de cada chave com eficiência. - A abordagem com janela percorre a tabela uma vez; a subconsulta correlacionada não.
DISTINCT ONno PostgreSQL pode usar o mesmo índice e costuma ser a opção mais rápida para uma única tabela.- Para registros de eventos com muitas inclusões, considere uma tabela materializada de registros mais recentes, atualizada incrementalmente.
Erros comuns
Preste atenção a estes pontos:
- Usar
MAX(date)e retornar apenas a data, não a linha completa. - Esquecer o critério de desempate, produzindo resultados não determinísticos quando as datas empatam.
- Filtrar pela condição depois da classificação, o que pode escolher uma linha que deveria ter sido excluída.
- Confundir "uma única linha mais recente" (
ROW_NUMBER) com "todas as linhas mais recentes empatadas" (RANK).
Verificação rápida
Escolha a consulta correta para obter o registro mais recente por chave.
Resumo: registro mais recente por chave
O padrão: PARTITION BY chave, ORDER BY carimbo de data/hora DESC (mais um critério de desempate único), mantenha rn = 1.
MAX(date)fornece a data, não a linha completa.- Sempre adicione um critério de desempate para garantir o determinismo.
- Use
RANK() = 1se quiser todas as linhas empatadas no carimbo de data/hora mais recente. - As condições de filtro devem ficar na consulta interna, antes da classificação.
DISTINCT ONdo PostgreSQL é uma alternativa concisa e rápida específica do dialeto.
Perguntas Frequentes
A aula “Mantendo a linha mais recente por chave” é grátis?
Sim — o texto completo de “Mantendo a linha mais recente por chave” é 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 “Mantendo a linha mais recente por chave”?
Use o padrão de registro mais recente por cliente, particionando pela chave e ordenando pela data. 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 4 de 4.
Quanto tempo leva a aula “Mantendo a linha mais recente por chave”?
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
- Linhas Top-N por grupo com ROW_NUMBER
- Lidando com empates em Top-N
- Eliminando duplicatas de linhas com segurança
- Mantendo a linha mais recente por chave