Ramos da InformáticaBanco de DadosSQL: Como Pegar o Registro com o Maior Valor...

SQL: Como Pegar o Registro com o Maior Valor de Cada Grupo

Aprenda como selecionar linhas com o maior valor em uma coluna no SQL. Descubra técnicas como subconsultas, funções de janela, e junções para otimizar suas consultas e resolver problemas comuns de banco de dados.

-

Não consegue retornar os outros dados da linha usando MAX()? Aprenda as melhores técnicas em SQL (Subconsultas, JOINs e ROW_NUMBER) para selecionar a linha com o maior valor.

Ao trabalhar com bases de dados relacionais, uma tarefa comum é selecionar linhas de uma tabela que contenham o maior valor em uma determinada coluna, respeitando condições específicas. Embora a tarefa pareça simples à primeira vista, as nuances da linguagem SQL e as diferenças entre bancos de dados tornam o problema mais interessante.

Este artigo aborda o tema em detalhes, explicando os conceitos envolvidos, apresentando diferentes abordagens para resolver o problema e analisando suas vantagens e desvantagens. Além disso, veremos exemplos práticos para diferentes bancos de dados, como MySQL, PostgreSQL, SQL Server e Oracle.

O Problema

Imagine que você tenha uma tabela chamada sales com as seguintes colunas e dados:

Dica de Leitura: Agora que você entendeu como selecionar linhas com o maior valor em uma determinada coluna, é importante pensar em como otimizar o desempenho dessas consultas, especialmente em bancos de dados grandes. Para isso, uma abordagem interessante é o uso de tecnologias como o Redis para melhorar a performance. Leia mais sobre como melhorar a performance em aplicações com bancos de dados relacionais usando Redis e descubra como essa combinação pode impulsionar a eficiência do seu sistema.

id salesperson amount
1 Alice 500
2 Bob 300
3 Alice 700
4 Bob 600
5 Charlie 400

Nosso objetivo é selecionar a linha de cada salesperson onde o amount é o maior.

Resultado Esperado

Para o exemplo acima, queremos o seguinte resultado:

id salesperson amount
3 Alice 700
4 Bob 600
5 Charlie 400

A lógica é simples: para cada vendedor (salesperson), selecione a linha com o maior valor de amount.

Conceitos-Chave

Antes de mergulharmos nas soluções, é importante entender os seguintes conceitos em SQL:

  1. Funções Agregadas:
    • A função MAX() é usada para determinar o maior valor em uma coluna. No entanto, ela sozinha não é suficiente para retornar a linha associada a esse valor.
  2. Agrupamento (GROUP BY):
    • Permite agrupar linhas com valores compartilhados em colunas específicas.
  3. Junções (JOIN):
    • Podem ser usadas para combinar tabelas ou subconjuntos da mesma tabela, resolvendo problemas onde precisamos comparar linhas.
  4. Subconsultas:
    • Subconsultas permitem que você execute uma consulta dentro de outra, geralmente para filtrar ou agregar resultados.
  5. CTEs (Common Table Expressions):
    • Disponíveis em bancos modernos, como PostgreSQL e SQL Server, ajudam a organizar consultas complexas.

Soluções Comuns

1. Subconsulta Simples com MAX()

A abordagem mais básica envolve uma subconsulta para determinar o maior valor de amount por vendedor e, em seguida, selecionar as linhas correspondentes.

SELECT id, salesperson, amount
FROM sales s1
WHERE amount = (
    SELECT MAX(amount)
    FROM sales s2
    WHERE s1.salesperson = s2.salesperson
);

Explicação:

  1. Para cada linha da tabela sales (representada por s1), verificamos o maior valor de amount para aquele salesperson usando uma subconsulta (s2).
  2. Apenas as linhas onde amount corresponde ao valor máximo são retornadas.

Vantagens:

  • Simples de entender e implementar.
  • Funciona em praticamente todos os bancos de dados.

Desvantagens:

  • Pode ser ineficiente em tabelas grandes, pois a subconsulta é executada para cada linha.

2. Usando ROW_NUMBER() ou RANK() (Bancos Avançados)

Bancos de dados modernos oferecem funções de janela, como ROW_NUMBER() e RANK(), que permitem numerar as linhas com base em critérios específicos.

WITH RankedSales AS (
    SELECT id, salesperson, amount,
           ROW_NUMBER() OVER (PARTITION BY salesperson ORDER BY amount DESC) AS rank
    FROM sales
)
SELECT id, salesperson, amount
FROM RankedSales
WHERE rank = 1;

Explicação:

  1. Criamos uma CTE chamada RankedSales onde numeramos as linhas de cada salesperson com base no valor de amount em ordem decrescente.
  2. Apenas as linhas com rank = 1 (maior valor) são selecionadas.

Vantagens:

  • Mais eficiente do que subconsultas em muitos casos.
  • Suporta empates ao usar RANK() (ex.: se dois vendedores tiverem o mesmo valor máximo).

Desvantagens:

  • Não está disponível em bancos mais antigos, como versões antigas do MySQL.

3. Junção com Subconsulta Agregada

Outra abordagem comum envolve calcular o valor máximo em uma subconsulta e, em seguida, unir os resultados com a tabela original.

SELECT s.id, s.salesperson, s.amount
FROM sales s
JOIN (
    SELECT salesperson, MAX(amount) AS max_amount
    FROM sales
    GROUP BY salesperson
) max_sales
ON s.salesperson = max_sales.salesperson AND s.amount = max_sales.max_amount;

Explicação:

  1. Na subconsulta, agrupamos por salesperson e calculamos o valor máximo de amount.
  2. A tabela resultante (max_sales) é unida com a tabela original (sales) para retornar as linhas correspondentes.

Vantagens:

  • Boa performance em bancos que otimizam junções.
  • Fácil de entender.

Desvantagens:

  • Mais código do que as soluções anteriores.

SQL: Selecionando Somente Linhas com o Maior Valor em uma Coluna

Ao trabalhar com bases de dados relacionais, uma tarefa comum é selecionar linhas de uma tabela que contenham o maior valor em uma determinada coluna, respeitando condições específicas. Embora a tarefa pareça simples à primeira vista, as nuances da linguagem SQL e as diferenças entre bancos de dados tornam o problema mais interessante.

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.

Este artigo aborda o tema em detalhes, explicando os conceitos envolvidos, apresentando diferentes abordagens para resolver o problema e analisando suas vantagens e desvantagens. Além disso, veremos exemplos práticos para diferentes bancos de dados, como MySQL, PostgreSQL, SQL Server e Oracle.


O Problema

Imagine que você tenha uma tabela chamada sales com as seguintes colunas e dados:

id salesperson amount
1 Alice 500
2 Bob 300
3 Alice 700
4 Bob 600
5 Charlie 400

Nosso objetivo é selecionar a linha de cada salesperson onde o amount é o maior.

Resultado Esperado

Para o exemplo acima, queremos o seguinte resultado:

id salesperson amount
3 Alice 700
4 Bob 600
5 Charlie 400

A lógica é simples: para cada vendedor (salesperson), selecione a linha com o maior valor de amount.


Conceitos-Chave

Antes de mergulharmos nas soluções, é importante entender os seguintes conceitos em SQL:

  1. Funções Agregadas:
    • A função MAX() é usada para determinar o maior valor em uma coluna. No entanto, ela sozinha não é suficiente para retornar a linha associada a esse valor.
  2. Agrupamento (GROUP BY):
    • Permite agrupar linhas com valores compartilhados em colunas específicas.
  3. Junções (JOIN):
    • Podem ser usadas para combinar tabelas ou subconjuntos da mesma tabela, resolvendo problemas onde precisamos comparar linhas.
  4. Subconsultas:
    • Subconsultas permitem que você execute uma consulta dentro de outra, geralmente para filtrar ou agregar resultados.
  5. CTEs (Common Table Expressions):
    • Disponíveis em bancos modernos, como PostgreSQL e SQL Server, ajudam a organizar consultas complexas.

Soluções Comuns

1. Subconsulta Simples com MAX()

A abordagem mais básica envolve uma subconsulta para determinar o maior valor de amount por vendedor e, em seguida, selecionar as linhas correspondentes.

sqlCopiar códigoSELECT id, salesperson, amount
FROM sales s1
WHERE amount = (
    SELECT MAX(amount)
    FROM sales s2
    WHERE s1.salesperson = s2.salesperson
);

Explicação:

  1. Para cada linha da tabela sales (representada por s1), verificamos o maior valor de amount para aquele salesperson usando uma subconsulta (s2).
  2. Apenas as linhas onde amount corresponde ao valor máximo são retornadas.

Vantagens:

  • Simples de entender e implementar.
  • Funciona em praticamente todos os bancos de dados.

Desvantagens:

  • Pode ser ineficiente em tabelas grandes, pois a subconsulta é executada para cada linha.

2. Usando ROW_NUMBER() ou RANK() (Bancos Avançados)

Bancos de dados modernos oferecem funções de janela, como ROW_NUMBER() e RANK(), que permitem numerar as linhas com base em critérios específicos.

sqlCopiar códigoWITH RankedSales AS (
    SELECT id, salesperson, amount,
           ROW_NUMBER() OVER (PARTITION BY salesperson ORDER BY amount DESC) AS rank
    FROM sales
)
SELECT id, salesperson, amount
FROM RankedSales
WHERE rank = 1;

Explicação:

  1. Criamos uma CTE chamada RankedSales onde numeramos as linhas de cada salesperson com base no valor de amount em ordem decrescente.
  2. Apenas as linhas com rank = 1 (maior valor) são selecionadas.

Vantagens:

  • Mais eficiente do que subconsultas em muitos casos.
  • Suporta empates ao usar RANK() (ex.: se dois vendedores tiverem o mesmo valor máximo).

Desvantagens:

  • Não está disponível em bancos mais antigos, como versões antigas do MySQL.

3. Junção com Subconsulta Agregada

Outra abordagem comum envolve calcular o valor máximo em uma subconsulta e, em seguida, unir os resultados com a tabela original.

sqlCopiar códigoSELECT s.id, s.salesperson, s.amount
FROM sales s
JOIN (
    SELECT salesperson, MAX(amount) AS max_amount
    FROM sales
    GROUP BY salesperson
) max_sales
ON s.salesperson = max_sales.salesperson AND s.amount = max_sales.max_amount;

Explicação:

  1. Na subconsulta, agrupamos por salesperson e calculamos o valor máximo de amount.
  2. A tabela resultante (max_sales) é unida com a tabela original (sales) para retornar as linhas correspondentes.

Vantagens:

  • Boa performance em bancos que otimizam junções.
  • Fácil de entender.

Desvantagens:

  • Mais código do que as soluções anteriores.

4. Solução Específica para MySQL (Antes da Versão 8.0)

Antes da versão 8.0, o MySQL não suportava funções de janela, mas ainda era possível obter o resultado usando truques como auto-junções.

SELECT s1.id, s1.salesperson, s1.amount
FROM sales s1
LEFT JOIN sales s2
ON s1.salesperson = s2.salesperson AND s1.amount < s2.amount
WHERE s2.id IS NULL;

Explicação:

  1. Fazemos uma junção onde s1.amount é menor que s2.amount.
  2. Apenas as linhas de s1 sem correspondências (s2.id IS NULL) são retornadas, indicando que são as maiores para aquele salesperson.

Vantagens:

  • Funciona em versões antigas do MySQL.

Desvantagens:

  • Complexidade maior do que as outras abordagens.

Desafios e Considerações

1. Linhas Empatadas

Se dois vendedores tiverem o mesmo valor máximo, algumas abordagens podem retornar apenas uma das linhas. Para incluir todas, substituímos ROW_NUMBER() por RANK() ou ajustamos as junções.

WITH RankedSales AS (
    SELECT id, salesperson, amount,
           RANK() OVER (PARTITION BY salesperson ORDER BY amount DESC) AS rank
    FROM sales
)
SELECT id, salesperson, amount
FROM RankedSales
WHERE rank = 1;

2. Indexação

Para tabelas grandes, indexar as colunas usadas em agrupamentos ou filtros (salesperson e amount) melhora significativamente o desempenho.

3. Cenários de Uso

  • Relatórios: Mostrar o melhor desempenho de cada vendedor.
  • Auditorias: Identificar transações mais altas em categorias específicas.
  • Ranking: Construir sistemas de pontuação ou classificações.

Conclusão

Selecionar linhas com o maior valor em uma coluna é uma tarefa essencial, mas cheia de nuances. A solução ideal depende do banco de dados usado, do tamanho da tabela e dos requisitos específicos do problema.

Em resumo:

  • Subconsultas: Simples, mas potencialmente menos eficientes.
  • Funções de Janela: Modernas e poderosas, ideais para bancos avançados.
  • Junções: Flexíveis e eficazes em muitos casos.

A escolha da abordagem correta pode fazer uma grande diferença em termos de legibilidade, eficiência e escalabilidade. Agora que você entende os princípios e estratégias, está pronto para aplicar esses conceitos nos seus próprios projetos!

Aqui estão algumas referências úteis para o artigo sobre como selecionar linhas com o maior valor em uma coluna no SQL:

Referências Técnicas e Documentação

  1. Documentação Oficial dos Bancos de Dados:
  2. Funções de Janela:
  3. SQL Joins e Subconsultas:

Perguntas Frequentes (FAQ): Selecionar a Linha do Maior Valor

Por que não posso usar apenas MAX(valor) e selecionar as outras colunas?

Esse é o erro mais comum no SQL. Ao usar uma função de agregação como o MAX(), as regras do SQL exigem que qualquer outra coluna no seu SELECT seja agrupada em um GROUP BY. Se o seu SGBD (como configurações antigas do MySQL) permitir executar a query sem o GROUP BY, ele retornará a maior data, mas os dados das outras colunas (como o nome do cliente) pertencerão a uma linha aleatória do grupo, e não àquela que possui o valor máximo.

Qual é a diferença entre ROW_NUMBER() e RANK() nesse cenário?

Ambas são funções de janela (Window Functions). O ROW_NUMBER() gera números sequenciais únicos (1, 2, 3…). Se dois vendedores tiverem empatado com o exato mesmo valor máximo de venda, o ROW_NUMBER() dará a posição “1” para o primeiro que ele ler, e “2” para o segundo (omitindo o segundo do resultado final). Já o RANK() respeita empates, atribuindo a posição “1” para ambos, garantindo que nenhum dado máximo seja omitido.

Qual método é o mais rápido em tabelas com milhões de registros?

Depende muito do SGBD e dos índices. Em bancos modernos (PostgreSQL, SQL Server, Oracle e MySQL 8+), a abordagem utilizando CTE e ROW_NUMBER() geralmente possui um plano de execução mais otimizado. No entanto, em bancos legados que não suportam funções de janela, a técnica do LEFT JOIN verificando onde a segunda tabela IS NULL costuma superar as subconsultas simples (desde que haja um índice na coluna do valor).

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

Como aprender a programar, um guia definitivo

Última atualização em 23/04/2026. Guia completo sobre: Como aprender a programar. Espero que este “guia” ou “manifesto”, como prefiro chamar, seja...

Stream Deck para Desenvolvedores: o Console de Comando do Futuro

Esqueça os streamers. Descubra como o Stream Deck se tornou o hardware essencial para Engenheiros de IA e Full...

Como Usar o Skills in Chrome no Brasil: Tutorial Completo de IA

A inteligência artificial já faz parte do nosso fluxo de trabalho, mas ter que reescrever os mesmos prompts repetidamente...

Context Engineering: Como Arquitetar Dados para LLMs e RAG

Na edição desta newsletter intitulada “Engenharia de Prompt: Não é só mais uma buzzword“: https://www.linkedin.com/pulse/engenharia-de-prompt-n%C3%A3o-%C3%A9-s%C3%B3-mais-uma-buzzword-de-souza-janones-tpkxf tratei sobre o tema...
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.

Aprender Idiomas com Google Tradutor: Na Prática

O Google está lançando um novo recurso experimental com tecnologia de IA no Google Tradutor, projetado para ajudar as...

Comunidades Internacionais de Desenvolvedores

Descubra as melhores comunidades internacionais de devs para 2026: GitHub, Stack Overflow, Discord e mais. Comparativo de salários Brasil vs. exterior e guia de carreira remota.

Mais Lidos

Editar React Direto: Guia Definitivo do React Grab

React Grab começou como uma ferramenta para copiar contexto...

Setup para Programadores: A Estação de Trabalho Eficiente

A configuração de uma estação de trabalho eficiente é...

Otimização de Performance no MySQL: Guia Avançado

Aprenda a otimizar a performance do MySQL. Guia prático...

Segurança em Código Python: Práticas Recomendadas

Fique atento às 10 melhores práticas recomendadas para alcançar...
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.

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.