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.
- Como o
GROUP BYcom 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 DISTINCTcom as mesmas colunas. - Se a ordem das colunas no
GROUP BYmuda o resultado (os grupos não mudam; a ordem das linhas, sim). - Como juntar
WHERE,HAVING,ORDER BYe 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 estado | Agrupando por estado e cidade |
|---|---|
| Pilha PI: 14 fichas | PI + Teresina: 10 · PI + Parnaíba: 1 · PI + Picos: 1 · PI + Oeiras: 1 · PI + Floriano: 1 |
| Pilha SP: 7 fichas | SP + São Paulo: 7 |
| Pilha CE: 7 fichas | CE + Fortaleza: 7 |
| Pilha PE: 2 fichas | PE + Recife: 2 |
| 4 pilhas | 8 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
clientesdá 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.
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 BYpode usar o apelidoclientescriado noSELECT.
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:
FROM: de qual tabela vêm as linhas.WHERE: quais linhas entram (antes de agrupar).GROUP BY: como as linhas viram pilhas.HAVING: quais pilhas ficam (depois de agrupar).SELECT: o que mostrar de cada pilha.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 doSELECTnoGROUP 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.
| Forma | Exemplo | Quando usar |
|---|---|---|
| Nomes das colunas | GROUP BY estado, cidade | Sempre que puder. É claro e funciona em todos os bancos. |
Posições no SELECT | GROUP BY 1, 2 | Consultas rápidas, de olhar e jogar fora. Evite em consultas que vão ficar guardadas. |
Apelido do SELECT | GROUP BY funcionario_id, ano | Quando a coluna é uma expressão (substr(…)). No SQL Server não funciona: lá, repita a expressão. |
| Repetir a expressão | GROUP BY funcionario_id, substr(data, 1, 4) | Quando a consulta precisa rodar em qualquer banco. |
Quando dá errado
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;
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.
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;.
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.
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(*) > ….
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.
- 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
SELECTnoGROUP 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 temGROUP 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
| Escrita | O que faz |
|---|---|
GROUP BY a, b | Um grupo para cada combinação de a e b que existe na tabela |
GROUP BY a, b, c | Divide 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, 2 | Agrupa 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 DESC | Garante a ordem das linhas; sem ele, a ordem não é garantida |
| Mensagem do SQLite | Quer 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 error | Faltou a vírgula antes de cidade |
near ";": syntax error | Vírgula sobrando no fim da lista |
near "GROUP": syntax error | GROUP BY fora do lugar (depois do ORDER BY, por exemplo) |
aggregate functions are not allowed in the GROUP BY clause | COUNT, SUM… dentro do GROUP BY |
no such function: ROLLUP | O SQLite não tem ROLLUP |
Exercícios
1. Complete o agrupamento
Complete para contar os produtos de cada combinação de categoria e fornecedor:
2. Quantos grupos?
Na Loja Aurora, a consulta SELECT estado, cidade, COUNT(*) FROM clientes GROUP BY estado, cidade; devolve quantas 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, bforma um grupo para cada combinação de valores deaeb; 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 BYnão muda os grupos. Para garantir a ordem das linhas, useORDER BY. WHEREfiltra linhas antes de agrupar;HAVINGfiltra 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
SELECTfora de uma função agregada tem de estar noGROUP BY. O SQLite não reclama se você esquecer, e mostra um valor de uma linha qualquer; os outros bancos dão erro.