Ramos da InformáticaBanco de DadosComo Retornar o Último Registro de Cada Grupo no...

Como Retornar o Último Registro de Cada Grupo no SQL

Aprenda como recuperar o último registro de cada grupo em SQL com técnicas avançadas para MySQL, PostgreSQL, SQL Server e Oracle. Otimize consultas e melhore o desempenho do banco de dados agora!

-

Ramos da Informática
JS TS IA

Pesquisa: Como você está usando IA na sua rotina Dev?

Responda em menos de 2 minutos e ajude a direcionar nossos próximos artigos técnicos, guias e conteúdos.

Responder Pesquisa →

Recuperar o último registro de cada grupo em um banco de dados é uma necessidade comum, mas que pode ser desafiadora dependendo do sistema de gerenciamento de banco de dados (SGDB) utilizado. Este artigo explora várias formas de resolver esse problema em diferentes SGDBs, como MySQL, PostgreSQL, SQL Server e Oracle, utilizando abordagens modernas e eficientes.


1. Entendendo o Problema

O objetivo é obter o último registro (ou o registro mais recente) de cada grupo baseado em uma ou mais colunas. Por exemplo, em uma tabela de vendas, você pode querer encontrar a venda mais recente de cada cliente.

Exemplo de Tabela:

id cliente_id data_venda valor
1 101 2024-01-10 200
2 102 2024-01-15 150
3 101 2024-01-20 300
4 102 2024-01-22 250

Resultado esperado: Queremos o último registro de cada cliente com base na coluna data_venda:

Dica de Leitura: Se você está buscando melhorar a performance das suas consultas SQL, especialmente aquelas que envolvem operações complexas como a recuperação do último registro de cada grupo, entender como otimizar o desempenho com tecnologias complementares pode ser crucial. Confira nosso artigo sobre Performance com Redis em Bancos Relacionais para descobrir como você pode acelerar suas aplicações.

id cliente_id data_venda valor
3 101 2024-01-20 300
4 102 2024-01-22 250

2. Soluções Gerais

2.1 Usando ROW_NUMBER()

O uso da função ROW_NUMBER() é uma abordagem moderna e eficiente suportada por muitos SGDBs.

Exemplo (SQL Server, PostgreSQL, Oracle):

sqlCopiar códigoWITH cte AS (
    SELECT 
        id, 
        cliente_id, 
        data_venda, 
        valor,
        ROW_NUMBER() OVER (PARTITION BY cliente_id ORDER BY data_venda DESC) AS row_num
    FROM vendas
)
SELECT id, cliente_id, data_venda, valor
FROM cte
WHERE row_num = 1;

Como Funciona:

  1. A função ROW_NUMBER() atribui um número a cada linha dentro de cada grupo (PARTITION BY cliente_id), ordenando por data_venda em ordem decrescente.
  2. No passo final, filtramos apenas os registros onde row_num = 1.

2.2 Usando DISTINCT ON

PostgreSQL oferece a funcionalidade DISTINCT ON, que é extremamente eficiente para este tipo de problema.

Exemplo (PostgreSQL):

sqlCopiar códigoSELECT DISTINCT ON (cliente_id) id, cliente_id, data_venda, valor
FROM vendas
ORDER BY cliente_id, data_venda DESC;

Como Funciona:

  1. DISTINCT ON retorna apenas o primeiro registro encontrado para cada grupo definido pela cláusula (cliente_id).
  2. A cláusula ORDER BY determina qual registro será considerado o “primeiro” para cada grupo.

2.3 Usando Subconsultas

Subconsultas correlacionadas funcionam em qualquer SGDB, incluindo MySQL.

Exemplo (MySQL, SQL Server, Oracle):

sqlCopiar códigoSELECT id, cliente_id, data_venda, valor
FROM vendas v1
WHERE data_venda = (
    SELECT MAX(data_venda)
    FROM vendas v2
    WHERE v1.cliente_id = v2.cliente_id
);

Como Funciona:

  1. Para cada registro da tabela vendas, a subconsulta encontra a data máxima (MAX(data_venda)) para o mesmo cliente_id.
  2. Apenas os registros com a maior data_venda são retornados.

Desvantagens:

  • Pode ser menos performático em tabelas grandes, já que a subconsulta é executada para cada linha.

2.4 Usando Funções de Agregação

Combinar GROUP BY com funções de agregação pode ser uma abordagem simples.

Exemplo (MySQL, PostgreSQL, SQL Server):

sqlCopiar códigoSELECT v1.id, v1.cliente_id, v1.data_venda, v1.valor
FROM vendas v1
JOIN (
    SELECT cliente_id, MAX(data_venda) AS max_data
    FROM vendas
    GROUP BY cliente_id
) v2
ON v1.cliente_id = v2.cliente_id AND v1.data_venda = v2.max_data;

Como Funciona:

  1. O subquery encontra a data máxima (MAX(data_venda) para cada cliente.
  2. O JOIN combina a tabela original com os resultados agregados para trazer os registros completos.

VAI GOSTAR: O que é normalização de banco de dados? – Descubra tudo sobre a normalização de banco de dados, incluindo as explicações detalhadas da 5NF e 2NF com exemplos práticos. Aprenda como melhorar a organização e a eficiência dos seus dados e otimize seus sistemas de forma profissional.


3. Abordagens Específicas por SGDB

3.1 MySQL (Antes do 8.0)

MySQL antes da versão 8.0 não suportava funções analíticas como ROW_NUMBER(). Nesse caso, o uso de subconsultas ou agregações é necessário.

Exemplo:

sqlCopiar códigoSELECT v1.*
FROM vendas v1
INNER JOIN (
    SELECT cliente_id, MAX(data_venda) AS max_data
    FROM vendas
    GROUP BY cliente_id
) v2
ON v1.cliente_id = v2.cliente_id AND v1.data_venda = v2.max_data;

3.2 MySQL 8.0 ou Superior

Com suporte a ROW_NUMBER():

english-interview-debugger.sh
$ grep -r "senior_dev_communication" ./career
[CRITICAL_ERROR] Código sênior detectado, mas fluência falhou no runtime.
Motivo: Travou na hora de explicar a arquitetura (System Design) em inglês para o gringo.

O mercado internacional não quer um robô de gramática. Quer um dev que saiba defender uma tomada de decisão técnica sob pressão. Destrave sua conversão na Preply com aulas particulares focadas em TI.

$ ./fix-english.sh --target=remote-job
Achar Professor Particular ➔
sqlCopiar códigoWITH cte AS (
    SELECT 
        id, cliente_id, data_venda, valor,
        ROW_NUMBER() OVER (PARTITION BY cliente_id ORDER BY data_venda DESC) AS row_num
    FROM vendas
)
SELECT id, cliente_id, data_venda, valor
FROM cte
WHERE row_num = 1;

3.3 PostgreSQL

Usar DISTINCT ON é geralmente a abordagem mais eficiente:

sqlCopiar códigoSELECT DISTINCT ON (cliente_id) id, cliente_id, data_venda, valor
FROM vendas
ORDER BY cliente_id, data_venda DESC;

3.4 SQL Server

Usando ROW_NUMBER():

sqlCopiar códigoWITH cte AS (
    SELECT 
        id, cliente_id, data_venda, valor,
        ROW_NUMBER() OVER (PARTITION BY cliente_id ORDER BY data_venda DESC) AS row_num
    FROM vendas
)
SELECT id, cliente_id, data_venda, valor
FROM cte
WHERE row_num = 1;

3.5 Oracle

Com funções analíticas:

SELECT id, cliente_id, data_venda, valor
FROM (
    SELECT 
        id, cliente_id, data_venda, valor,
        ROW_NUMBER() OVER (PARTITION BY cliente_id ORDER BY data_venda DESC) AS row_num
    FROM vendas
)
WHERE row_num = 1;

4. Desempenho e Otimizações

4.1 Índices

  • Adicionar um índice nas colunas usadas para particionamento e ordenação (cliente_id, data_venda) pode melhorar significativamente o desempenho.

4.2 Tamanho da Tabela

  • Em tabelas muito grandes, preferir abordagens que minimizam leituras redundantes, como DISTINCT ON (PostgreSQL) ou ROW_NUMBER().

4.3 Benchmarking

  • Execute benchmarks em seu ambiente para comparar o desempenho de diferentes abordagens, especialmente se a tabela tiver milhões de registros.

5. Conclusão

Recuperar o último registro de cada grupo pode ser feito de várias formas, dependendo do SGDB e das necessidades específicas do sistema. Funções analíticas, como ROW_NUMBER(), são geralmente as mais eficientes e flexíveis, mas alternativas como DISTINCT ON e subconsultas também são úteis em cenários específicos. Entender as capacidades do SGDB escolhido e ajustar a abordagem para o contexto é essencial para garantir consultas rápidas e eficientes.

Referências Sobre o Tema

Aqui estão algumas referências confiáveis e úteis para aprofundar seu conhecimento sobre como recuperar o último registro em cada grupo em SQL:


Documentação Oficial

  1. MySQL:
    • Documentação sobre Funções Analíticas:
      MySQL ROW_NUMBER()
    • Documentação sobre Funções Agregadas:
      MySQL Aggregate Functions
  2. PostgreSQL:
  3. SQL Server:
  4. Oracle:

Livros

Para quem gosta de se aprofundar com leitura, livros oferecem uma visão mais técnica e estruturada.

Ambientes Práticos

A prática é essencial para dominar SQL. Aqui estão algumas ferramentas para experimentar e executar consultas.

VAI GOSTAR:

Perguntas Frequentes (FAQ): Último Registro por Grupo no SQL

Qual é a forma mais eficiente de pegar o último registro no PostgreSQL?

No PostgreSQL, a sintaxe nativa SELECT DISTINCT ON (coluna_grupo) aliada a um ORDER BY coluna_grupo, coluna_data DESC é, na esmagadora maioria dos casos, a forma mais limpa e performática de retornar o registro mais recente de cada grupo, superando o desempenho de CTEs e Subconsultas.

Como retornar a linha mais recente no MySQL sem Window Functions?

Se você utiliza uma versão do MySQL inferior a 8.0 (que não suporta ROW_NUMBER()), a melhor abordagem é usar um INNER JOIN com uma subconsulta. Você agrupa os dados na subconsulta usando GROUP BY e MAX(data), e depois faz um JOIN dessa tabela temporária com a tabela original, cruzando o ID e a data máxima.

Por que usar MAX() diretamente não retorna os outros dados da linha corretamente?

O erro clássico de agrupamento ocorre porque o SQL padrão exige que qualquer coluna no SELECT que não faça parte de uma função de agregação (como MAX() ou SUM()) deva estar explicitamente no GROUP BY. Se você usar MAX(data) e tentar selecionar a coluna “valor” sem agrupá-la, o banco de dados retornará um valor aleatório daquele grupo, e não necessariamente o valor correspondente à data máxima.

O que faz a cláusula PARTITION BY no ROW_NUMBER()?

O PARTITION BY funciona de maneira similar ao GROUP BY, mas sem “achatar” as linhas em um único resultado. Ele divide o conjunto de resultados em “partições” (ou grupos) com base em uma coluna (ex: ID do Cliente). O ROW_NUMBER() então recomeça a contagem a partir de 1 para cada nova partição, ordenando os dados internamente conforme a instrução ORDER BY.

Ramos da Informática
JS TS IA

Pesquisa: Como você está usando IA na sua rotina Dev?

Responda em menos de 2 minutos e ajude a direcionar nossos próximos artigos técnicos, guias e conteúdos.

Responder Pesquisa →
Ramos da Informática
Ramos da Informáticahttps://ramosdainformatica.com.br
Ramos da Informática é um hub de comunidade dedicado a linguagens de programação, banco de dados, DevOps, Internet das Coisas (IoT), tecnologias da Indústria 4.0, cibersegurança e startups. Com curadoria de conteúdos de qualidade, o projeto é mantido por Ramos de Souza Janones.

Mais recentes

NVIDIA Lança Cosmos 3: Nova Plataforma de IA Física para Robôs Humanoides e Fábricas Inteligentes

NVIDIA apresenta plataforma full-stack para robôs humanoides, robotáxis e fábricas inteligentes Cosmos 3, robôs humanoides e ferramentas para robotáxis são...

Repositórios e Skills Essenciais para Claude Code, Cursor e Codex

Se você já integrou o Claude Code, Cursor ou Codex no seu fluxo de trabalho, sabe que o jogo...

17 Ferramentas No-Code para Validar Seu Negócio

No mundo dos negócios, construir um Produto Mínimo Viável (MVP) não pode ser sinônimo de queimar o caixa da...

Extensões PostgreSQL: Substitua Redis, MongoDB e Kafka com SQL

Dominar as extensões PostgreSQL deixou de ser apenas uma opção para se tornar a principal estratégia de arquitetura em...
E-Zine Dev

Evolua para Sênior

Estratégias de Node.js, arquitetura Limpa e IA que nunca publicamos no blog. Junte-se a +10.000 devs.

Assinar Gratuitamente Zero spam. Cancele quando quiser.

State of AI 2026: A Maturidade da Inteligência Artificial

A inteligência artificial deixou definitivamente o território das experimentações e se consolidou como uma peça de infraestrutura fundamental no...

Construindo um Servidor MCP Personalizado com Node.js

Um guia prático para construir seu próprio servidor MCP para enriquecer as respostas de ferramentas de IA com contexto...

Mais Lidos

Como escolher mini PC para home lab de desenvolvedor em 2026

Se você está se perguntando qual mini PC para...

Melhores Livros de Inteligência Artificial para Desenvolvedores

A inteligência artificial (IA) está cada vez mais presente...

Blockchain e Impacto Social: Como Criptomoedas Mudam Vidas

Iniciativa impactMarket leva Renda Básica Universal e mudanças extremamente...

Como Validar o Novo CNPJ Alfanumérico (2026): Código e Regex

CNPJ é a sigla para Cadastro Nacional de Pessoas...
E-Zine Dev

Evolua para Sênior

Estratégias de Node.js, arquitetura Limpa e IA que nunca publicamos no blog. Junte-se a +10.000 devs.

Assinar Gratuitamente Zero spam. Cancele quando quiser.

Recursos da Comunidade

Carreira Internacional

JOB NA GRINGA

Meta de Salário Remoto
U$ 5.000/mês

O mapa completo para programadores do Brasil conquistarem contratos internacionais e mudarem de vida financeira.

  • Vagas exclusivas semanais: Membros acessam vagas com 7 dias de antecedência.
  • Workshops e lives gravadas: Buscar vagas não é óbvio. Nós te mostraremos como.
  • 498 Portais de vagas: Que contratam Brasileiros direto na sua dashboard.
  • Mentorias com Recrutadores: Encontros semanais ao vivo com Erika Linares.
  • Inglês diário com foco em conversação: Treine para entrevistas num ambiente sem julgamentos.
  • Suporte pós-contratação: Contabilidade e recebimento legal com a menor taxa.
Garantir Minha Vaga

Inscrição segura via Hotmart

Você vai gostarrelacionados
Continue aprendendo

E-Zine Dev Ramos

Quer dominar arquitetura e IA?

Junte-se a +10.000 profissionais. Receba semanalmente estratégias de Node.js, React e IA que nunca publicamos no blog.

Assinar Gratuitamente Zero spam. Cancele quando quiser.