SQL Agrupando por Mais de uma Coluna

Na aula GROUP BY, a Ana descobriu quantos clientes a Loja Aurora tem em cada estado: 14 no Piauí, 7 em São Paulo, 7 no Ceará e 2 em Pernambuco. Agora o gerente quer mais detalhe: "dentro do Piauí, quantos são de Teresina e quantos são do interior?". Para responder, a Ana precisa agrupar por duas colunas ao mesmo tempo, estado e cidade. É só listar as duas no GROUP BY, separadas por vírgula, mas há algumas pegadinhas no caminho, e uma delas o SQLite deixa passar sem reclamar.

Você vai aprender
  • Como o GROUP BY com duas colunas forma um grupo para cada combinação de valores.
  • Quantos grupos saem, e por que esse número é igual ao de um SELECT DISTINCT com as mesmas colunas.
  • Se a ordem das colunas no GROUP BY muda o resultado (os grupos não mudam; a ordem das linhas, sim).
  • Como juntar WHERE, HAVING, ORDER BY e várias funções agregadas na mesma consulta.
  • Agrupar por três colunas e por uma expressão (o ano de uma data).
  • A armadilha da coluna esquecida no GROUP BY, que o SQLite aceita e os outros bancos recusam, e os erros reais de sintaxe.

Todos os exemplos rodam de verdade no seu navegador, no banco da Loja Aurora: o quadro "Resultado" embaixo de cada código é o SQLite respondendo. As mensagens de erro também são reais.


A ideia: pilhas dentro de pilhas

Imagine as 30 fichas de cliente da loja em cima da mesa. Agrupar por estado é separar as fichas em pilhas, uma por estado, e contar cada pilha. Agrupar por estado e cidade é pegar cada pilha de estado e dividi-la de novo, por cidade:

Agrupando só por estadoAgrupando por estado e cidade
Pilha PI: 14 fichasPI + Teresina: 10 · PI + Parnaíba: 1 · PI + Picos: 1 · PI + Oeiras: 1 · PI + Floriano: 1
Pilha SP: 7 fichasSP + São Paulo: 7
Pilha CE: 7 fichasCE + Fortaleza: 7
Pilha PE: 2 fichasPE + Recife: 2
4 pilhas8 pilhas

Duas fichas só caem na mesma pilha se forem iguais nas duas colunas: mesmo estado e mesma cidade. Cada combinação diferente vira um grupo, e cada grupo vira uma linha do resultado.


1. Relembrando: uma coluna

Este é o ponto de partida, da aula GROUP BY: um grupo por estado.

SELECT estado, COUNT(*) AS clientes
FROM clientes
GROUP BY estado;

Quatro linhas, uma por estado. O Piauí tem 14 clientes, mas a consulta não diz de quais cidades eles são.


2. Duas colunas: estado e cidade

Para dividir cada estado por cidade, a Ana acrescenta cidade em dois lugares: na lista do SELECT (para a coluna aparecer) e no GROUP BY (para ela entrar na formação dos grupos).

SELECT estado, cidade, COUNT(*) AS clientes
FROM clientes
GROUP BY estado, cidade;
SELECT estado, cidade,
As duas colunas do agrupamento, para cada linha mostrar qual grupo ela representa.
COUNT(*) AS clientes
A função agregada: conta as linhas de cada grupo. O apelido clientes dá nome à coluna (aula Apelidos (AS)).
FROM clientes
A tabela de onde vêm as 30 fichas.
GROUP BY estado, cidade
Group by = "agrupe por". Com duas colunas separadas por vírgula, o grupo é formado pela combinação das duas: linhas com o mesmo estado e a mesma cidade ficam juntas.

Agora o gerente tem a resposta: dos 14 clientes do Piauí, 10 são de Teresina e 4 são do interior (Floriano, Oeiras, Parnaíba e Picos, um em cada). Repare que os números do Piauí somam 10 + 1 + 1 + 1 + 1 = 14, o mesmo total da consulta anterior. Agrupar por mais colunas não perde nem inventa linhas: só divide os mesmos clientes em pilhas menores.

Por que o estado, se a cidade já diz tudo?

Na Loja Aurora, cada cidade aparece em um só estado, então agrupar só por cidade daria os mesmos 8 grupos. Mas no Brasil existem cidades com o mesmo nome em estados diferentes (há uma Bom Jesus no Piauí e outra no Rio Grande do Sul, por exemplo). Agrupando por estado e cidade, duas cidades homônimas nunca se misturam numa pilha só.

Experimente: a coluna vip vale 1 para os clientes VIP e 0 para os outros. Mude a consulta para contar, em cada estado, quantos clientes são VIP e quantos não são: acrescente vip logo depois de estado no SELECT e no GROUP BY. Devem sair 7 grupos.

SELECT estado, COUNT(*) AS clientes
FROM clientes
GROUP BY estado;
SELECT estado, vip, COUNT(*) AS clientes
FROM clientes
GROUP BY estado, vip;

Por que 7 e não 8 (4 estados × 2 valores de vip)? Porque Pernambuco não tem nenhum cliente VIP. Isso leva à próxima seção.


3. Quantos grupos saem?

O GROUP BY só cria grupos para as combinações que existem na tabela. Não existe cliente de "PI + São Paulo", então essa pilha nunca aparece. E também não existe cliente VIP em Pernambuco, então "PE + 1" não aparece no exercício acima.

Uma forma de conferir quantos grupos vão sair é perguntar quais combinações diferentes existem, com o DISTINCT (aula SELECT DISTINCT):

SELECT DISTINCT estado, cidade
FROM clientes;

As mesmas 8 combinações, só que sem a contagem e em outra ordem. A regra vale sempre: o número de linhas de um GROUP BY a, b é o número de combinações diferentes de a e b. O DISTINCT mostra as combinações; o GROUP BY mostra as combinações e calcula alguma coisa sobre cada uma.


4. A ordem das colunas no GROUP BY

E se a Ana escrever GROUP BY cidade, estado, invertido?

SELECT cidade, estado, COUNT(*) AS clientes
FROM clientes
GROUP BY cidade, estado;

Os grupos são os mesmos 8, com as mesmas contagens: "Teresina + PI" é a mesma pilha que "PI + Teresina". O que mudou foi a ordem das linhas: desta vez saíram em ordem alfabética de cidade. Isso acontece porque, para montar os grupos, o SQLite costuma ordenar as linhas pelas colunas do GROUP BY, na ordem em que você as escreveu. Mas isso é um detalhe de funcionamento interno, e não uma promessa: o padrão SQL não garante ordem nenhuma sem ORDER BY.

Quando a ordem importa, diga qual você quer com ORDER BY (aula ORDER BY). Aqui, estados em ordem alfabética e, dentro de cada estado, as cidades com mais clientes primeiro:

SELECT estado, cidade, COUNT(*) AS clientes
FROM clientes
GROUP BY estado, cidade
ORDER BY estado, clientes DESC;
ORDER BY estado,
Primeiro critério: o estado, de A a Z (CE, PE, PI, SP).
clientes DESC
Desempate dentro do mesmo estado: a contagem, do maior para o menor (descending, "decrescente"). O ORDER BY pode usar o apelido clientes criado no SELECT.

Teresina, com 10, subiu para o topo do Piauí. As quatro cidades do interior empataram com 1 cliente; entre elas, a ordem não está garantida. Se quiser uma ordem fixa também para os empates, acrescente mais um critério: ORDER BY estado, clientes DESC, cidade.


5. Com WHERE, HAVING e várias contas

Tudo o que você já sabe sobre GROUP BY continua valendo com duas colunas. Os produtos da loja têm uma categoria (categoria_id) e um fornecedor (fornecedor_id). A Ana quer saber, só nos eletrônicos (categoria 2), quantos produtos cada fornecedor entrega e a faixa de preço de cada um:

SELECT categoria_id, fornecedor_id,
       COUNT(*)   AS produtos,
       MIN(preco) AS mais_barato,
       MAX(preco) AS mais_caro
FROM produtos
WHERE categoria_id = 2
GROUP BY categoria_id, fornecedor_id;
WHERE categoria_id = 2
Filtra as linhas antes de agrupar: só os 7 eletrônicos entram nas pilhas.
GROUP BY categoria_id, fornecedor_id
Uma pilha para cada par categoria + fornecedor que sobrou.
COUNT(*), MIN(preco), MAX(preco)
Três contas feitas dentro de cada pilha: quantos produtos, o preço mais baixo e o mais alto (aulas MIN() e MAX()).

O fornecedor 3 entrega 5 eletrônicos, de 29,90 a 189,99; o fornecedor 5 entrega 2. Agora, a loja inteira: quais combinações de categoria e fornecedor têm 3 produtos ou mais? Filtrar grupos é trabalho do HAVING (aula HAVING):

SELECT categoria_id, fornecedor_id, COUNT(*) AS produtos
FROM produtos
GROUP BY categoria_id, fornecedor_id
HAVING COUNT(*) >= 3
ORDER BY produtos DESC;

Sem o HAVING, seriam 20 combinações; com ele, sobram 7. A ordem das partes da consulta é sempre a mesma, tenha o GROUP BY uma coluna ou dez:

  1. FROM: de qual tabela vêm as linhas.
  2. WHERE: quais linhas entram (antes de agrupar).
  3. GROUP BY: como as linhas viram pilhas.
  4. HAVING: quais pilhas ficam (depois de agrupar).
  5. SELECT: o que mostrar de cada pilha.
  6. ORDER BY: em que ordem mostrar.

6. Três colunas (ou mais)

Não há limite prático: cada coluna nova divide as pilhas mais uma vez. Por estado, cidade e VIP:

SELECT estado, cidade, vip, COUNT(*) AS clientes
FROM clientes
GROUP BY estado, cidade, vip;

Teresina, que era uma pilha de 10, virou duas: 8 clientes comuns e 2 VIP. O mesmo aconteceu com Fortaleza e São Paulo. Resultado: 11 grupos. Quanto mais colunas, mais pilhas e menores elas ficam. Com colunas demais, cada pilha acaba tendo uma linha só, e o agrupamento deixa de resumir alguma coisa.


7. Agrupando por uma expressão: funcionário e ano

A coluna do GROUP BY não precisa ser uma coluna da tabela: pode ser uma conta feita em cada linha. Os pedidos têm a data no formato 2024-01-05, e os 4 primeiros caracteres são o ano. A função substr(data, 1, 4) recorta esses 4 caracteres (ela tem aula própria em Funções de Texto). Com ela, a Ana conta quantos pedidos cada funcionário atendeu em cada ano:

SELECT funcionario_id,
       substr(data, 1, 4) AS ano,
       COUNT(*) AS pedidos
FROM pedidos
GROUP BY funcionario_id, ano
ORDER BY funcionario_id, ano;
substr(data, 1, 4) AS ano
Recorta o ano da data e chama o resultado de ano.
GROUP BY funcionario_id, ano
Agrupa pelo funcionário e pelo apelido ano. O SQLite aceita o apelido do SELECT no GROUP BY; nem todo banco aceita (veja "Nos outros bancos").

São 6 funcionários que atendem pedidos (2 a 7) e 3 anos (2024, 2025 e 2026), e todos atenderam em todos os anos: 6 × 3 = 18 grupos. Por exemplo, o funcionário 2 atendeu 6 pedidos em 2024, 5 em 2025 e 4 em 2026.


Formas diferentes de escrever o mesmo GROUP BY

As três consultas abaixo formam exatamente os mesmos grupos:

SELECT estado, cidade, COUNT(*) AS clientes
FROM clientes
GROUP BY estado, cidade;
SELECT estado, cidade, COUNT(*) AS clientes
FROM clientes
GROUP BY 1, 2;

Na segunda, 1 e 2 querem dizer "a 1ª e a 2ª coluna do SELECT". É curto, mas frágil: se alguém inserir uma coluna no começo do SELECT, o agrupamento muda sem ninguém perceber. A terceira forma é a da seção 7: usar um apelido do SELECT no GROUP BY, que ajuda quando a coluna é uma expressão comprida.

FormaExemploQuando usar
Nomes das colunasGROUP BY estado, cidadeSempre que puder. É claro e funciona em todos os bancos.
Posições no SELECTGROUP BY 1, 2Consultas rápidas, de olhar e jogar fora. Evite em consultas que vão ficar guardadas.
Apelido do SELECTGROUP BY funcionario_id, anoQuando a coluna é uma expressão (substr(…)). No SQL Server não funciona: lá, repita a expressão.
Repetir a expressãoGROUP BY funcionario_id, substr(data, 1, 4)Quando a consulta precisa rodar em qualquer banco.

Quando dá errado

A coluna esquecida no GROUP BY (o SQLite não avisa!)

A Ana pôs cidade no SELECT, mas esqueceu de pô-la no GROUP BY:

SELECT estado, cidade, COUNT(*) AS clientes
FROM clientes
GROUP BY estado;

O que acontece: nenhum erro, e um resultado mentiroso. A linha "PI | Teresina | 14" parece dizer que Teresina tem 14 clientes, mas Teresina tem 10: o 14 é o Piauí inteiro. Os grupos foram formados só pelo estado (4 pilhas), e para a coluna cidade o SQLite pegou a cidade de uma linha qualquer de cada pilha.

A documentação do SQLite chama isso de bare column ("coluna solta"): uma coluna que não está numa função agregada nem no GROUP BY. Ela diz que o valor vem de uma das linhas do grupo e que "normalmente você não sabe qual linha é usada". O SQLite permite de propósito, para alguns truques avançados; quase sempre, porém, é um esquecimento.

Como consertar: toda coluna do SELECT que não está dentro de uma função agregada (COUNT, SUM, MIN…) tem de estar no GROUP BY. Aqui: GROUP BY estado, cidade. Ou, se você queria mesmo o total por estado, tire cidade do SELECT.

Missão: esta consulta diz que Teresina tem 14 clientes, o que é falso. Conserte-a para que mostre a contagem certa de cada cidade (8 linhas, com Teresina valendo 10).

SELECT estado, cidade, COUNT(*) AS clientes
FROM clientes
GROUP BY estado;
SELECT estado, cidade, COUNT(*) AS clientes
FROM clientes
GROUP BY estado, cidade;
Faltou a vírgula entre as colunas
SELECT estado, cidade, COUNT(*)
FROM clientes
GROUP BY estado cidade;

A mensagem: near "cidade": syntax error, "perto de cidade: erro de sintaxe". O SQLite leu GROUP BY estado e esperava, em seguida, uma vírgula, um HAVING, um ORDER BY ou o fim da consulta; encontrou outra palavra solta e parou ali. A palavra citada na mensagem é onde ele percebeu o problema; o erro de verdade é a falta da vírgula logo antes dela.

Como consertar: GROUP BY estado, cidade.

Vírgula sobrando no fim
SELECT estado, cidade, COUNT(*)
FROM clientes
GROUP BY estado, cidade,;

A mensagem: near ";": syntax error. Depois de uma vírgula, o SQLite espera mais uma coluna; veio o ponto e vírgula. Acontece muito quando se apaga a última coluna da lista e a vírgula fica para trás.

Como consertar: apague a vírgula final: GROUP BY estado, cidade;.

GROUP BY depois do ORDER BY
SELECT estado, cidade, COUNT(*)
FROM clientes
ORDER BY estado
GROUP BY estado, cidade;

A mensagem: near "GROUP": syntax error. As partes de uma consulta têm ordem fixa: WHERE, depois GROUP BY, depois HAVING, e o ORDER BY por último.

Como consertar: troque as duas linhas de lugar: GROUP BY estado, cidade e só então ORDER BY estado.

Uma função agregada dentro do GROUP BY
SELECT estado, COUNT(*)
FROM clientes
GROUP BY estado, COUNT(*);

A mensagem: aggregate functions are not allowed in the GROUP BY clause, "funções agregadas não são permitidas na cláusula GROUP BY". Faz sentido: o COUNT(*) conta as linhas de uma pilha, e as pilhas ainda nem existem enquanto o GROUP BY está sendo montado.

Como consertar: o GROUP BY leva só as colunas que formam os grupos (GROUP BY estado). As contas ficam no SELECT; para filtrar pelo resultado de uma conta, use HAVING COUNT(*) > ….

Subtotais com ROLLUP (não existe no SQLite)

Em outros bancos, ROLLUP acrescenta linhas de subtotal (um total por estado e um total geral). Quem copia uma consulta dessas para o SQLite recebe:

SELECT estado, cidade, COUNT(*)
FROM clientes
GROUP BY ROLLUP(estado, cidade);

A mensagem: no such function: ROLLUP, "não existe a função ROLLUP". O SQLite não conhece ROLLUP e, como ele está escrito com parênteses, acha que é uma função. A forma do MySQL, GROUP BY estado, cidade WITH ROLLUP, dá near "WITH": syntax error.

Como fazer no SQLite: rode uma consulta para os detalhes (GROUP BY estado, cidade) e outra para os subtotais (GROUP BY estado). Juntar as duas num resultado só é assunto da aula UNION ALL.

Nos outros bancos
  • A coluna esquecida vira erro. O MySQL, com o modo ONLY_FULL_GROUP_BY (ligado por padrão), recusa a consulta da coluna esquecida com o erro 1055 ("… is not in GROUP BY clause and contains nonaggregated column …"). O SQL Server responde que a coluna "is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause". O PostgreSQL também recusa. Só o SQLite aceita calado, por isso o cuidado é seu.
  • Apelido no GROUP BY. O SQL Server não aceita o apelido do SELECT no GROUP BY (a documentação dele diz isso com todas as letras): repita a expressão inteira.
  • Subtotais. PostgreSQL e SQL Server têm GROUP BY ROLLUP (estado, cidade); o MySQL tem GROUP BY estado, cidade WITH ROLLUP. Ilustrativo, não roda no SQLite:
SELECT estado, cidade, COUNT(*) AS clientes
FROM clientes
GROUP BY ROLLUP (estado, cidade);

Referência rápida

EscritaO que faz
GROUP BY a, bUm grupo para cada combinação de a e b que existe na tabela
GROUP BY a, b, cDivide cada grupo de a, b mais uma vez, por c
GROUP BY a, substr(data, 1, 4)Agrupa por uma coluna e por uma expressão
GROUP BY 1, 2Agrupa pela 1ª e 2ª colunas do SELECT (frágil)
WHERE …Filtra linhas antes de agrupar
HAVING …Filtra grupos depois de agrupar
ORDER BY a, contagem DESCGarante a ordem das linhas; sem ele, a ordem não é garantida
Mensagem do SQLiteQuer dizer
(nenhuma, mas o número está errado)Uma coluna do SELECT ficou fora do GROUP BY e fora das funções agregadas
near "cidade": syntax errorFaltou a vírgula antes de cidade
near ";": syntax errorVírgula sobrando no fim da lista
near "GROUP": syntax errorGROUP BY fora do lugar (depois do ORDER BY, por exemplo)
aggregate functions are not allowed in the GROUP BY clauseCOUNT, SUM… dentro do GROUP BY
no such function: ROLLUPO SQLite não tem ROLLUP

Exercícios

1. Complete o agrupamento

Complete para contar os produtos de cada combinação de categoria e fornecedor:

SELECT categoria_id, fornecedor_id, COUNT(*) FROM produtos categoria_id fornecedor_id;

2. Quantos grupos?

Na Loja Aurora, a consulta SELECT estado, cidade, COUNT(*) FROM clientes GROUP BY estado, cidade; devolve quantas linhas?

Linhas:

3. O que muda entre GROUP BY estado, cidade e GROUP BY cidade, estado?

4. A Ana rodou SELECT estado, cidade, COUNT(*) FROM clientes GROUP BY estado; no SQLite. O que acontece?

5. A Ana quer, por categoria e fornecedor, só as combinações com estoque total acima de 200. Onde vai a condição SUM(estoque) > 200?

Missão final: o estoque por categoria e fornecedor

Missão: o comprador da loja quer uma lista com, para cada combinação de categoria e fornecedor, quantos produtos existem (coluna produtos) e a soma do estoque deles (coluna estoque). Mas só as combinações com estoque total acima de 200 unidades. As colunas devem ser, nesta ordem: categoria_id, fornecedor_id, produtos, estoque.

SELECT categoria_id, COUNT(*) AS produtos
FROM produtos
GROUP BY categoria_id;
SELECT categoria_id, fornecedor_id,
       COUNT(*) AS produtos,
       SUM(estoque) AS estoque
FROM produtos
GROUP BY categoria_id, fornecedor_id
HAVING SUM(estoque) > 200
ORDER BY estoque DESC;

Os números de categoria e fornecedor ainda são só números: "categoria 1, fornecedor 1" não diz muito ao comprador. Para trocar esses números pelos nomes ("Papelaria", "Distribuidora Piauí Center"), é preciso buscar a informação em outra tabela. É exatamente o assunto do próximo grupo de aulas, que começa em Tabelas que se Relacionam.


Resumo

  • GROUP BY a, b forma um grupo para cada combinação de valores de a e b; cada grupo vira uma linha do resultado.
  • Só aparecem as combinações que existem. O número de grupos é o mesmo de SELECT DISTINCT a, b.
  • A ordem das colunas no GROUP BY não muda os grupos. Para garantir a ordem das linhas, use ORDER BY.
  • WHERE filtra linhas antes de agrupar; HAVING filtra grupos depois. Várias funções agregadas podem ser calculadas no mesmo agrupamento.
  • Dá para agrupar por três ou mais colunas, e por expressões como substr(data, 1, 4).
  • Toda coluna do SELECT fora de uma função agregada tem de estar no GROUP BY. O SQLite não reclama se você esquecer, e mostra um valor de uma linha qualquer; os outros bancos dão erro.