FolioPierEstudos de TI

Contar, somar e agrupar

Nota 8 de 41 · 4 min de leitura
Nesta página
  1. As funções de resumo
  2. Agrupar com GROUP BY
  3. Filtrar os grupos com HAVING
  4. Ordenar o resumo
  5. Cuidados com os resumos

Muitas perguntas do atendimento pedem um resumo, e não uma lista: quantas vendas o caixa 01 registrou no dia, qual foi o total vendido por caixa ou se existe um produto cadastrado duas vezes. As funções de resumo e o agrupamento respondem a essas perguntas em uma única consulta, sem a contagem manual das linhas.

As funções de resumo

As funções de resumo, também chamadas de funções de agregação, transformam várias linhas em um único valor:

  • COUNT(*): conta as linhas;
  • COUNT(cliente_id): conta apenas as linhas em que a coluna está preenchida;
  • COUNT(DISTINCT caixa): conta os valores diferentes da coluna;
  • SUM(total): soma os valores;
  • AVG(total): calcula a média;
  • MIN(data_venda) e MAX(data_venda): mostram o menor e o maior valor.

Uma consulta pode reunir várias funções e respeita o filtro do WHERE, que escolhe as linhas antes do resumo:

  • SELECT COUNT(*), SUM(total) FROM vendas WHERE caixa = 'CX01' AND situacao = 'F';: mostra a quantidade e o valor total das vendas finalizadas do caixa 01.

Agrupar com GROUP BY

A cláusula GROUP BY separa as linhas em grupos, conforme o valor de uma ou mais colunas, e calcula o resumo de cada grupo:

  • SELECT caixa, COUNT(*), SUM(total) FROM vendas WHERE situacao = 'F' GROUP BY caixa;: mostra uma linha para cada caixa, com a quantidade e o total das vendas finalizadas.

Toda coluna que aparece no SELECT sem uma função de resumo precisa aparecer também no GROUP BY. A partir do MySQL 5.7, essa regra vale por padrão, e uma consulta que a descumpre recebe o erro 1055, de coluna fora do agrupamento. As versões anteriores aceitavam essa consulta e mostravam um valor qualquer do grupo na coluna solta, sem nenhum aviso. Por isso, uma consulta antiga pode passar a falhar depois de uma atualização do MySQL.

Filtrar os grupos com HAVING

O WHERE filtra as linhas antes do agrupamento. O HAVING filtra os grupos depois do agrupamento e pode usar o resultado das funções de resumo:

  • SELECT caixa, COUNT(*) FROM vendas WHERE situacao = 'C' GROUP BY caixa HAVING COUNT(*) > 20;: mostra os caixas com mais de vinte vendas canceladas.

O HAVING também encontra valores repetidos. Para saber se algum código de produto foi cadastrado mais de uma vez, a consulta agrupa pelo código e mantém apenas os grupos com mais de uma linha:

  • SELECT codigo, COUNT(*) FROM produtos GROUP BY codigo HAVING COUNT(*) > 1;

Ordenar o resumo

O resultado agrupado pode ser ordenado pelo próprio resumo. Para facilitar a leitura, a função recebe um apelido com a palavra AS, e o apelido pode ser usado no ORDER BY:

  • SELECT caixa, SUM(total) AS faturamento FROM vendas WHERE situacao = 'F' GROUP BY caixa ORDER BY faturamento DESC;: mostra os caixas do maior para o menor faturamento.

Cuidados com os resumos

  • Uma soma de valores do tipo DECIMAL é exata, enquanto uma soma de valores aproximados pode acumular diferenças de centavos.
  • Um resumo sem filtro de período percorre a tabela inteira e pode ser demorado em tabelas grandes. Uma condição no WHERE, como um intervalo de datas, limita as linhas examinadas.
  • Os mesmos filtros precisam ser usados quando um resumo é comparado com um relatório do sistema. Um relatório que exclui as vendas canceladas não pode ser comparado com uma contagem que as inclui.

No suporte

Uma contagem diferente da esperada costuma ter origem nos filtros. Antes de concluir que faltam dados, convém conferir se o WHERE da consulta usa o mesmo período, a mesma situação e os mesmos caixas do relatório ou da tela usados na comparação.

Para guardar

  • COUNT, SUM, AVG, MIN e MAX resumem várias linhas em um valor.
  • O WHERE filtra as linhas antes do resumo, e o HAVING filtra os grupos depois.
  • Toda coluna fora das funções de resumo precisa estar no GROUP BY.
  • A partir do MySQL 5.7, o descumprimento dessa regra gera o erro 1055.
  • GROUP BY com HAVING COUNT(*) > 1 encontra valores repetidos.
Como descobrir se existem produtos com o mesmo código cadastrados mais de uma vez?

Com o agrupamento pelo código, mantendo apenas os grupos com mais de uma linha: SELECT codigo, COUNT(*) FROM produtos GROUP BY codigo HAVING COUNT(*) > 1;. O HAVING filtra os grupos depois da contagem.

Uma consulta com GROUP BY funcionava em um servidor antigo e passou a dar o erro 1055 em um MySQL mais novo. O que mudou?

As versões a partir do MySQL 5.7 exigem, por padrão, que toda coluna do SELECT esteja no GROUP BY ou dentro de uma função de resumo. O servidor antigo aceitava a consulta e escolhia um valor qualquer do grupo para a coluna solta. A correção é incluir a coluna no GROUP BY ou resumi-la com uma função.

Publicado a partir do Obsidian · FolioPier