Voltar para a lista de artigos Artigos
13 minutos de leitura

7 Comum GROUP BY Erros

Você está cometendo esses erros com o GROUP BY em SQL? Descubra o que eles são, como evitá-los e como corrigi-los.

A declaração GROUP BY da SQL pode rapidamente desvendar poderosas informações de dados. No início, usar GROUP BY pode parecer fácil - por exemplo, ao criar relatórios SQL básicos que você apresentará aos tomadores de decisão de negócios. Mas enquanto aprende este poderoso recurso, você pode ficar preso a erros estranhos ou obter resultados incorretos causados por declarações GROUP BY mal escritas. Se você estiver se sentindo como se as coisas não estivessem se somando ao seu uso do GROUP BY, continue lendo. Neste artigo, explicarei os erros mais comuns do GROUP BY e como você pode evitá-los.

Pare de cometer estes 7 erros comuns do GROUP BY

1. Esquecimento de GROUP BY Funções Agregadas

Você usa SELECT declarações com a cláusula GROUP BY quando deseja agrupar e organizar linhas em grupos específicos e depois realizar um cálculo específico de cada grupo.

O erro mais comum GROUP BY é esquecer de escrever GROUP BY dentro da declaração SELECT.

Aqui está um exemplo. Imagine que você tem a tabela receitasque contém 100 registros e seis colunas. Esta tabela armazena o número de visualizações (no_of_views) por cada receita publicada em um famoso site de culinária:

meal_categorynameauthorno_of_viewsno_of_views_lst_mthauthor_id
Cold appetizerMarinated CheeseMarta107104906211
SoupsPumpkin soupJohn68856693772
dessertsBanana CheesecakeAlly131944NULL3
drinksPaloma PicanteLuke72027713124
Bread and pastrySour Cream DoughnutsJohn50935527912
dessertsReal Strawberry CupcakesLisa17626811693911
Soupspotato soupMary64796643886
..................
..................
..................
Bread and pastryCider DoughnutsTim53896511608

tabela de receitas

Aqui está uma breve descrição das colunas da tabela:

  • meal_category - A categoria da receita (sopa, bebidas, sobremesas, etc.).
  • name - O nome da receita.
  • author - O nome do autor.
  • no_of_views - O número de visualizações (total de páginas/receitas visualizadas) no mês corrente.
  • no_of_views_lst_mth - O número de visualizações (total de páginas/receitas visualizadas) no mês anterior.
  • author_id - O número de identificação único do autor.

Digamos que você queira contar o número de receitas em cada categoria de refeição. Se você escrever a declaração como esta (sem GROUP BY no final) ...

SELECT 
  meal_category,
  count(*) AS total_recipes 
FROM recipes ;

... a maioria dos motores SQL lhe dará um erro. Alguns motores, no entanto, produzirão resultados estranhos e indesejados. Estou usando o MySQL e quando executo esta declaração, eu recebo isto:

meal_categorytotal_recipes
Cold appetizer100

Resultado sem GROUP BY

100 é a contagem total de todas as receitas do conjunto de dados e a categoria de refeições "Aperitivo frio" é apenas uma categoria em cada dez. Para corrigir este tipo de erro, é necessário adicionar um GROUP BY meal_category no final da declaração. (Caso contrário, seu resultado no MySQL simplesmente não faz sentido).

O SELECT correto se parece com isto:

SELECT 
  meal_category,
  count(*) AS total_recipes 
FROM recipes
GROUP BY meal_category ;

Aqui está uma breve explicação do que está acontecendo:

  • Os registros são fundidos com base na categoria de refeição. Por exemplo, as sobremesas são um grupo, as sopas outro, os pratos principais ainda outro, etc. A coluna meal_category é especificada após GROUP BY; ela também é listada em SELECT.
  • Para cada grupo, estamos usando COUNT(*) para contar o número total de receitas nesse grupo.

Eu não vou mergulhar profundamente na sintaxe aqui, mas eu definitivamente sugeriria que você lesse GROUP BY in SQL Explained ou Using GROUP BY in SQL para mais detalhes.

Como você pode ver, o resultado é como esperávamos:

meal_categorytotal_recipes
Bread and pastry7
Cold appetizer6
desserts20
drinks7
Main dishes20
Salads8
Side dishes12
Soups17
Warm appetizer3

Resultado válido de GROUP BY

2. Confundindo ONDE e HAVING

Talvez você gostaria de ver apenas aquelas categorias de refeições que têm mais de 10 receitas. Muitos iniciantes escreveriam esta pergunta:

SELECT 
  meal_category,
  count(*) AS total_recipes 
FROM recipes
WHERE count(*) > 10 
GROUP BY meal_category ;

Esta declaração retornará um erro porque você não pode usar funções agregadas em uma cláusula WHERE. WHERE é usado com GROUP BY quando você quer filtrar as linhas antes de agrupá-las.

Em nosso exemplo, queremos filtrar as linhas após o agrupamento; em casos como este, precisamos usar a cláusula HAVING:

SELECT 
  meal_category,
  count(*) AS total_recipes 
FROM recipes
           GROUP BY meal_category
HAVING count(*) > 10  ;

Este mal entendido sobre a diferença entre HAVING e WHERE é o segundo erro mais comum com GROUP BY.

Vamos esclarecer esta diferença com mais dois exemplos.

Exemplo 1 - Como exibir categorias de refeições com vistas de 1M+

Uma declaração que exibe apenas categorias com mais de 1 milhão de páginas vistas no total pode ser escrita assim:

SELECT 
  meal_category,
  sum(no_of_views) AS total 
FROM recipes 
GROUP BY meal_category
HAVING sum(no_of_views) >1000000;

Aqui estamos usando HAVING porque queremos filtrar os registros após terem sido agrupados. O resultado é apresentado abaixo:

meal_categorytotal
desserts2969324
Main dishes1323981
Side dishes1662910
Soups1100911

Exemplo com HAVING

Exemplo 2 - O desempenho de John em cada categoria de refeição

Esta consulta extrai apenas as receitas de John e calcula seu desempenho:

SELECT 
  meal_category, 
  sum(no_of_views) AS total 
FROM recipes 
WHERE author = ‘John’ 
GROUP BY meal_category;

Estamos usando WHERE porque precisamos filtrar os registros (portanto, só obtemos os dados de John) antes de colocarmos os registros em grupos por categoria de refeição. Veja como fica o resultado:

meal_categorytotal
Bread and pastry50935
desserts301869
drinks147745
Main dishes279934
Salads88097
Side dishes415864
Soups393253
Warm appetizer85570

Os KPIs de John

HAVING e WHERE estão bem descritos em nossos artigos Qual é a diferença entre WHERE e HAVING Clauses in SQL? e 5 Exemplos de GROUP BY. Se você gostaria de ver mais exemplos sobre este tópico, sugiro que comece por aí.

3. Listagem de uma coluna dentro do SELECT mas não no GROUP BY

Agora suponha que você queira ver o número total de visualizações por meal_category e author. Podemos fazer isso? - ?só precisamos acrescentar a coluna do autor à nossa consulta anterior:

SELECT 
  meal_category,
  author,
  sum(no_of_views) AS total 
FROM recipes 
GROUP BY meal_category;

Isto lhe parece bem? É claro que não; ele vai lançar um erro na maioria dos motores SQL. Por exemplo, a Oracle lhe dirá "erro: Não é uma expressão "GROUP BY". Por que este erro confuso? O que está faltando aqui?

Bem, o motor SQL não sabe como calcular o total para cada autor porque não o incluímos na cláusula GROUP BY; o autor do atributo não está listado dentro da cláusula GROUP BY. Este é outro erro comum com a cláusula GROUP BY.

Vamos corrigir esta consulta e executá-la mais uma vez:

SELECT 
  meal_category,
  author,
  sum(no_of_views) AS total 
FROM recipes 
GROUP BY meal_category, author;

O resultado é:

meal_categoryauthortotal
Bread and pastryDino53789
Bread and pastryJohn50935
Bread and pastryMarta52998
Bread and pastryMary52904
Bread and pastryPatricia51451
Bread and pastryTim106226
.........
.........
.........
SoupsMary125731
SoupsMonte128356
SoupsPatricia255574
SoupsTim132532
Warm appetizerJohn85570
Warm appetizerLisa82960
Warm appetizerMary87560

Agora isto parece estar bem. Lembre-se, as colunas não agregadas que estão listadas em SELECT também devem ser listadas em GROUP BYEm nosso caso, as colunas não agregadas são meal_category e author, que agora estão em SELECT e GROUP BY.

Você não lista colunas que estão dentro de funções agregadas em GROUP BY. Em nosso exemplo, a coluna no_of_views é usada na função agregada SUM() e, portanto, não está listada na cláusula GROUP BY.

Se você gostaria de saber mais sobre este tópico, confira nosso artigo GROUP BY Cláusula: Você conhece bem? Ele explica porque as colunas SELECTed precisam aparecer na cláusula GROUP BY. Além disso, Como corrigir um erro "Não é um erro de GROUP BY Expressão" dá mais exemplos relacionados a este tipo de erro.

4. Não Agrupar por uma Chave Exclusiva

Agora vamos tentar algo mais. Suponha que queiramos obter o número médio de páginas vistas para cada autor de receita. A consulta seguinte calcula o número médio total de page views para cada autor usando o nome do autor:

SELECT 
  author,
  avg(no_of_views) 
FROM recipes 
GROUP BY author;

Ao olhar para o resultado, você notará que Lisa tem uma média de 116101,5 page views:

authoravg(NO_OF_VIEWS)
Ally106545
Dino94667.9091
John88163.35
Lisa116101.5
Luke104591
Marta119789.1667
Mary101040.0588
Monte84794
Patricia81911.1333
Tim76185.375

GROUP BY autor - mas os nomes não são únicos

No entanto, na verdade, temos dois autores chamados Lisa em nossa mesa. Quando agrupamos os resultados pela coluna do autor, os dois Lisas são calculados em média juntos. Por quê? Porque estamos usando uma coluna não única no GROUP BY. Isto significa que nem todos os valores de agrupamento têm que ser únicos. Se quisermos ver a média de cada Lisa separadamente, devemos adicionar author_id (uma coluna única) à lista GROUP BY:

SELECT 
  author, author_id
  avg(no_of_views) 
FROM recipes 
GROUP BY author, author_id;

Agora vemos como as receitas de Lisa(id=11) são muito mais vistas do que as receitas de Lisa(id=5):

authorauthor_idavg(no_of_views)
Ally3106545
Dino794667.9091
John288163.35
Lisa585798
Lisa11146405
Luke4104591
Marta1119789.1667
Mary6101040.0588
Monte984794
Patricia1081911.1333
Tim876185.375

GROUP BY com autor e autor_id

É importante pensar sempre em agrupar chaves. Os valores de agrupamento devem ser únicos e devem representar cada grupo da maneira desejada. Caso contrário, você obterá resultados imprecisos, confusos e possivelmente um GROUP BY erro.

5. CONTA(distinta) e COUNT(*) confusas

Se você estiver curioso para ver o número total de autores para cada categoria de refeição, você pode escrever uma declaração GROUP BY para calcular isso. Vamos usar COUNT(*) e recuperar o número de autores em cada categoria:

SELECT 
  meal_category, 
  count(*) 
FROM recipes 
GROUP BY meal_category;

Aqui está o resultado - mas não é o que você esperava, não é?

meal_categorycount(*)
Bread and pastry7
Cold appetizer6
desserts20
drinks7
Main dishes20
Salads8
Side dishes12
Soups17
Warm appetizer3

Este é o número total de receitas em cada categoria, não o número total de autores. Por que isso acontece? Bem, COUNT(*) conta todas as fileiras de cada grupo. A receita da tabela contém informações sobre uma recipe nível - cada registro é uma receita. Esta consulta conta as receitas (linhas) em cada categoria, não os autores da receita.

Um autor pode ter muitas receitas em cada categoria, então para obter as informações que você deseja, você deve contar autores distintos (usando COUNT(distinct author) ao invés de COUNT(*)) dentro de cada grupo. Este é um erro muito comum no GROUP BY.

Então, quando você deve usar COUNT(*), COUNT(expression) e COUNT(distinct expression)?

Vamos dar uma olhada em um exemplo:

SELECT 
  meal_category, 
  count(distinct author), 
  count(author),
  count(*) 
FROM recipes 
GROUP BY meal_category;
meal_categorycount(distinct author)count(author)count(*)
Bread and pastry677
Cold appetizer266
desserts82020
drinks577
Main dishes92020
Salads688
Side dishes81212
Soups61717
Warm appetizer333

A diferença entre COUNT(*) e COUNT(expression) é visível se estivermos fazendo cálculos em uma coluna que tem alguns valores em falta. Quando valores faltantes estão presentes, COUNT(*) contará todos os registros de um grupo e COUNT(expression) contará apenas valores não-nulos.

No exemplo acima, COUNT(*) e COUNT(author) dão exatamente o mesmo resultado porque a coluna do autor não tem nenhum valor NULL.

COUNT(distinct author) nos dá o número de autores distintos para cada categoria, que não é o mesmo que COUNT(*). Por exemplo, a categoria de refeição aperitivo fria contém seis receitas de dois autores distintos. COUNT(*) conta o número de receitas (registros) em cada categoria, enquanto COUNT(distinct author) conta o número de autores distintos.

Portanto, se você gostaria de exibir o número total de autores distintos por cada categoria de refeição, use COUNT(distinct author). Aqui está a consulta correta:

SELECT 
  meal_category, 
  count(distinct author)
FROM recipes 
GROUP BY meal_category;
GROUP BY meal_category;

Para uma explicação mais detalhada, veja Qual é a diferença entre COUNT(*), COUNT(1), COUNT(nome da coluna), e COUNT(nome da coluna DISTINCT)?

6. Problemas na utilização de funções agregadas com NULLs

Este é outro problema de "valor em falta". Digamos que você queira calcular o número médio total de pontos de vista do mês anterior para cada categoria. Seu colega calculou esses números, mas eles gostariam que você verificasse o resultado duas vezes.

Aqui está sua pergunta:

SELECT
      meal_category,
      avg(no_of_views_lst_mth) as average,
  FROM recipes 
GROUP BY meal_category;

E o que você recebe é ...

meal_categoryaverage
Bread and pastry52274.8571
Cold appetizer95584.2
desserts144349.7222
drinks72551.7143
Main dishes61350.8889
Salads90798.875
Side dishes139765.25
Soups64978.8824
Warm appetizer78390.6667

O resultado parece bom e você está confiante quando se trata da exatidão de sua consulta. Entretanto, seu colega obteve números ligeiramente diferentes:

meal_categoryaverage
Bread and pastry52274.8571
Cold appetizer79653.5
desserts129914.75
drinks72551.7143
Main dishes55215.8
Salads90798.875
Side dishes139765.25
Soups64978.8824
Warm appetizer78390.6667

O que acabou de acontecer? Por que os resultados diferentes?

Em poucas palavras, os diferentes resultados surgem de diferentes interpretações dos valores em falta.

A coluna no_of_views_lst_mth representa o número total de page views no mês anterior. Se uma receita foi criada no mês atual, esta coluna será NULL para aquela linha.

Por exemplo, a receita de Cheesecake de Banana da Ally foi escrita no mês corrente, portanto não há estatísticas para o mês anterior:

meal_categorynameauthorno_of_viewsno_of_views_lst_mthauthor_id
dessertsBanana CheesecakeAlly131944NULL3

O cheesecake de banana foi publicado no mês corrente

Agora, vamos voltar a essas médias e seus diferentes resultados. As médias são calculadas como a soma total de no_of_views_lst_mth dividida pelo número total de registros. Se você usar a função AVG() e as NULLs estiverem presentes, o motor simplesmente ignora as NULLs e faz cálculos sem elas. Isto é o que aconteceu quando você executou sua consulta - os NULLs foram omitidos. Em alguns casos, você vai querer substituir os NULLs por 0 (porque a lógica comercial dita); foi o que seu colega fez, o que produziu números ligeiramente diferentes. Aqui está a pergunta de seu colega:

SELECT
      meal_category,
           avg(CASE WHEN no_of_views_lst_mth is null 
            THEN 0 
            ELSE no_of_views_lst_mth END) AS average
FROM recipes 
GROUP BY meal_category;

Observe como as médias destas duas consultas tratam os NULLs de forma diferente. Por exemplo, a categoria "sobremesas" contém NULLs. Assim, a primeira consulta omite estas linhas e não as conta para o número total de linhas; isto dá o valor 144349,72. A segunda consulta substitui todos os NULLs por zero e conta estas linhas na média, dando um valor menor de 129914,75.

Eu diria que ambas as consultas poderiam ser válidas, dependendo de como você quer calcular as médias.

7. Usando COUNT(*) com GROUP BY e um LEFT JOIN

Usar GROUP BY com uma declaração LEFT JOIN pode ser bastante confuso - especialmente com COUNT(). Vamos ver como COUNT(*) e COUNT(expression) funcionam em um LEFT JOIN.

Vamos supor que alguém no marketing tem a seguinte tabela, recipes_campaigns. Ela contém informações sobre o número de campanhas realizadas em cada categoria de refeição no mês corrente:

meal_categorycampaigns
Bread and pastry2
Cold appetizer1
desserts3
drinks0
Main dishes3
Salads1
Side dishes2
Soups3
Warm appetizer0
brunch1
sandwiches0

receitas_campaign

Além dos dados em recipes_campaignsO comerciante também quer ver o número de receitas para cada categoria de refeição. Para isso, precisaremos das informações do recipes mesa. Portanto, vamos juntar estas duas tabelas e calcular o número de receitas usando COUNT(*), desta forma:

SELECT 
      a.meal_category,
      count(*),
     FROM recipes_campaigns a 
LEFT JOIN recipes b ON a.meal_category=b.meal_category
GROUP BY a.meal_category;

Aqui está o resultado:

meal_categorycount(*)
Bread and pastry7
brunch1
Cold appetizer6
desserts20
drinks7
Main dishes20
Salads8
sandwiches1
Side dishes12
Soups17
Warm appetizer3

Isto não é o que esperávamos. A tabela recipe não contém nenhuma receita na categoria "brunch", então por que então conseguimos essa 1 no resultado? Isto acontece porque COUNT() é aplicado ao resultado LEFT JOIN! Quando você LEFT JOIN duas tabelas, a categoria 'brunch' estará presente na saída - mesmo que não haja receitas ou categorias correspondentes no recipe mesa.

Como podemos consertar isso? Se usarmos COUNT(expression) em vez de COUNT(*), teremos o resultado que queremos:

SELECT 
      a.meal_category,
      count(author_id),
FROM recipes_campaigns a 
LEFT JOIN recipes b ON a.meal_category=b.meal_category
GROUP BY a.meal_category;

Uma vez que você administre isto, você obtém:

meal_categorycount(author_id)
Bread and pastry7
brunch0
Cold appetizer6
desserts20
drinks7
Main dishes20
Salads8
sandwiches0
Side dishes12
Soups17
Warm appetizer3

Aqui, COUNT(author_id) conta apenas os valores não-NULL em author_id após a execução do LEFT JOIN. Não há nenhum valor author_id para a categoria 'brunch'; em outras palavras, é NULL e o resultado para essa categoria é 0.

Você Pode Resolver GROUP BY Erros!

Através de vários exemplos, exploramos GROUP BY e os erros mais comuns que os iniciantes freqüentemente cometem. Espero que agora você tenha uma melhor noção de como GROUP BY funciona e o que está causando esses erros estranhos ou resultados confusos.

GROUP BY é realmente muito importante na criação de relatórios. Se você quiser aprender como construir bons relatórios, recomendo nossa Como Criar Relatórios Básicos em SQL curso. Ele tem muitos exercícios interativos que lhe permitem ganhar experiência escrevendo GROUP BY consultas para relatórios. E mais experiência certamente reduz a possibilidade de erros!