Como encontrar itens associados ao maior ou ao menor valor de uma lista no MySQL – Elias Praciano
Categories
Banco de dados Tutoriais

Como encontrar itens associados ao maior ou ao menor valor de uma lista no MySQL

Use as funções MAX() e MIN() do MySQL para encontrar o maior e o menor valor de uma relação associado ao item a que se referem. Veja alguns exemplos práticos que demonstram como fazer esta operação.

Para listar itens e ainda associá-los aos maiores ou menores valores use funções do MySQL em conjunto com as funções MAX() e MIN().
Veja alguns exemplos em que 2 queries são combinadas para obter resultados mais significativos.
As funções MIN() e MAX() são úteis para encontrar os extremos de uma relação de valores. O problema é que, ás vezes, queremos também saber a que item na tabela o valor em questão se encontra associado.
em uma relação de clientes correntistas, podemos usar a função MAX() para determinar qual o maior valor de crédito. O problema a ser resolvido é o de determinar exatamente a quem pertence o tal valor.
Veja um exemplo prático, no qual vamos determinar qual o maior valor de créditos possuído por cliente, na tabela CadastroClientes:

SELECT MAX(CreditosCliente) FROM CadastroClientes;

Como você pode ver, abaixo, o maior valor é 4992:

+----------------------+
| MAX(CreditosCliente) |
+----------------------+
|                 4992 |
+----------------------+
1 row in set (0.01 sec)

E se você quiser saber a que cliente este valor está associado?
Uma das soluções mais óbvias seria a seguinte:

SELECT NomeCliente, MAX(CreditosCliente) FROM CadastroClientes WHERE CreditosCliente = MAX(CreditosClente);

ERROR 1111 (HY000): Invalid use of group function

Infelizmente, ela não funciona.
Por mais que a lógica desta query pareça boa (ela não é), o fato é que funções agregadas, tais como MIN() e MAX(), não podem ser usadas em cláusulas WHERE.
A intenção da consulta é determinar qual registro tem o maior valor de crédito e exibir o nome do cliente associado a este valor.
O problema é que enquanto eu e você entendemos a consulta, pro MySQL ela não faz sentido algum.
Ela não funcionou porque, o MySQL usa a cláusla WHERE para determinar quais registros selecionar, mas só conhece o valor de uma função agregada depois de selecionar os registros a partir dos quais o valor da função é determinado.
A declaração se contradiz, portanto.
A solução, abaixo, é uma gambiarra e, embora chegue à conclusão correta, não responde diretamente ao enunciado:

SELECT NomeCliente, CreditosCliente FROM CadastroClientes ORDER BY CreditosCliente DESC LIMIT 1;
+------------------+-----------------+
| NomeCliente      | CreditosCliente |
+------------------+-----------------+
| Camille Thornton |            4992 |
+------------------+-----------------+
1 row in set (0.00 sec)

Você pode solucionar o problema usando uma abordagem em 2 estágios ou um subselect.
No primeiro estágio, atribuo o maior valor de créditos da tabela à variável CreditoMax:

SELECT @CreditoMax := MAX(CreditosCliente) FROM CadastroClientes;
+-------------------------------------+
| @CreditoMax := MAX(CreditosCliente) |
+-------------------------------------+
|                                4992 |
+-------------------------------------+
1 row in set (0.00 sec)

No segundo estágio, já tenho condições de criar uma consulta que encontre o valor máximo, relacionado ao cliente:

SELECT NomeCliente AS Cliente, @CreditoMax AS "Créditos" FROM CadastroClientes WHERE CreditosCliente = @CreditoMax;
+------------------+-----------+
| Cliente          | Créditos  |
+------------------+-----------+
| Camille Thornton |      4992 |
+------------------+-----------+
1 row in set (0.00 sec)

Nas versões mais atuais do MySQL, é possível resolver o problema com uma subselect, em apenas uma linha de código:

SELECT NomeCliente AS Cliente, CreditosCliente AS "Créditos" FROM CadastroClientes WHERE CreditosCliente = (SELECT MAX(CreditosCliente) FROM CadastroClientes);
+------------------+----------+
| Cliente          | Créditos |
+------------------+----------+
| Camille Thornton |     4992 |
+------------------+----------+
1 row in set (0.00 sec);

Mais um exemplo

No próximo exemplo, vou usar uma tabela que contém a Bíblia.
O objetivo é estabelecer qual o menor versículo presente no livro.
Primeiro, vamos estabelecer quantos caracteres tem o menor versículo da bíblia:

SELECT MIN(LENGTH(textover)) FROM bibliakjv;
+-----------------------+
| MIN(LENGTH(textover)) |
+-----------------------+
|                    13 |
+-----------------------+
1 row in set (0.02 sec)

Que tal uma resposta mais completa — que mostre a quantidade de caracteres do menor versículo da bíblia e o texto do mesmo?
Novamente, vejamos como solucionar o problema em 2 estágios (definindo uma variável e operando com ela, em seguida):

SELECT @MenorVerso := MIN(LENGTH(textover)) FROM bibliakjv;
+--------------------------------------+
| @MenorVerso := MIN(LENGTH(textover)) |
+--------------------------------------+
|                                   13 |
+--------------------------------------+
1 row in set (0.01 sec)

Uma vez atribuído o valor da menor quantidade de caracteres à variável @MenorVerso, vamos usá-lo na próxima consulta:

SELECT numliv AS "Livro", numcap AS "Capítulo", numver AS "Versículo", textover AS "Texto do versículo" FROM bibliakjv WHERE LENGTH(textover) = @MenorVerso\G
*************************** 1. row ***************************
             Livro: 5
          Capítulo: 5
         Versículo: 17
Texto do versículo: Não matarás. 
Núm. de caracteres: 13
1 row in set (0.02 sec)

Note que, na minha versão da Bíblia, há um espaço a mais no versículo, logo após o ponto final — que é contado e, portanto, dá 13 caracteres ao versículo. Paciência… 😉
Se você prefere uma solução usando uma subquery, lá vai:

SELECT numliv AS "Livro", numcap AS "Capítulo", numver AS "Versículo", textover AS "Texto do versículo", @MenorVerso AS "Núm. de caracteres" FROM bibliakjv WHERE LENGTH(textover) = (SELECT MIN(LENGTH(textover)) FROM bibliakjv)\G
*************************** 1. row ***************************
             Livro: 5
          Capítulo: 5
         Versículo: 17
Texto do versículo: Não matarás.
Núm. de caracteres: 13
1 row in set (0.05 sec)

By Elias Praciano

Autor de tecnologia (livre, de preferência), apaixonado por programação e astronomia.
Fã de séries, como "Rick and Morty" e "BoJack Horseman".
Me siga no Twitter e vamos trocar ideias!

One reply on “Como encontrar itens associados ao maior ou ao menor valor de uma lista no MySQL”

Obrigado professor! Mesmo assim não entendo porque não esta funcionando estou testando ate no ambiente do próprio Mysql e da um valor diferente do menor, não sei se tem a ver com o fato de eu usar números não inteiros, mas agradeço muito obrigado.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.