Seu navegador não oferece leitura em voz alta. Você pode ler o guia normalmente.
Agrupar linhas e resumi-las com COUNT, SUM, AVG, MIN e MAX é um dos temas de SQL mais cobrados, porque tem regras claras e pegadinhas previsíveis. Os exemplos abaixo usam dados fictícios e foram executados em um banco de teste para conferir cada número.
Dados de partida
Tabela servidor, a mesma dos outros guias de SQL deste site:
| id | nome | unidade_id | cargo | horas_extras | tempo_servico |
|---|---|---|---|---|---|
| 1 | Ana Lima | 1 | Analista | 10 | 5 |
| 2 | Bruno Souza | 1 | Tecnico | 4 | 12 |
| 3 | Carla Dias | 2 | Analista | NULL | 3 |
| 4 | Diego Alves | 2 | Analista | 8 | 9 |
| 5 | Elisa Rocha | 3 | Tecnico | 0 | 7 |
| 6 | Fabio Nunes | NULL | Analista | 6 | 2 |
| 7 | Gabi Matos | 2 | Tecnico | NULL | 15 |
Tabela unidade: 1 Protocolo, 2 Compras, 3 Arquivo, 4 Ouvidoria.
Funções de agregação
Uma função de agregação recebe várias linhas e devolve um valor. As cinco clássicas:
| Função | O que faz |
|---|---|
COUNT(*) |
conta linhas |
COUNT(coluna) |
conta valores não nulos da coluna |
SUM(coluna) |
soma, ignorando NULL |
AVG(coluna) |
média, ignorando NULL |
MIN / MAX |
menor e maior valor |
Sobre a tabela inteira:
SELECT COUNT(*), COUNT(horas_extras), COUNT(DISTINCT cargo) FROM servidor;
Resultado: 7, 5 e 2. Há sete linhas, mas só cinco têm horas_extras preenchida, e existem dois cargos distintos.
SUM(horas_extras) é 28 (10+4+8+0+6). AVG(horas_extras) é 5,6: a soma 28 dividida por 5, não por 7, porque os dois NULL saem do cálculo. Se a regra de negócio diz que ausência vale zero, use AVG(COALESCE(horas_extras, 0)), que dá 28 / 7 = 4,0. A escolha muda a resposta, e a prova gosta disso.
GROUP BY
GROUP BY forma grupos de linhas com o mesmo valor na(s) coluna(s) indicada(s), e a agregação é calculada por grupo.
SELECT cargo, COUNT(*) FROM servidor GROUP BY cargo;
Resultado: Analista 4, Tecnico 3.
Agora por unidade, com várias agregações:
SELECT unidade_id, COUNT(*) AS n, SUM(horas_extras) AS tot,
AVG(horas_extras) AS media, MAX(tempo_servico) AS maior
FROM servidor
GROUP BY unidade_id ORDER BY unidade_id;
| unidade_id | n | tot | media | maior |
|---|---|---|---|---|
| NULL | 1 | 6 | 6,0 | 2 |
| 1 | 2 | 14 | 7,0 | 12 |
| 2 | 3 | 8 | 8,0 | 15 |
| 3 | 1 | 0 | 0,0 | 7 |
Dois detalhes: o NULL forma um grupo próprio (Fabio), e na unidade 2 a média é 8,0 porque Carla e Gabi, com NULL, ficam fora do cálculo (só o valor de Diego conta). Para obter 2,67 (8 dividido por 3) seria preciso tratar o NULL como zero. A posição do grupo NULL na ordenação varia conforme o sistema.
Regra da lista do SELECT
Em uma consulta com GROUP BY, cada coluna do SELECT deve estar no GROUP BY ou dentro de uma função de agregação. SELECT nome, cargo, COUNT(*) ... GROUP BY cargo é inválido no padrão, pois nome não é único por grupo. Alguns sistemas aceitam por extensão, mas a resposta de prova segue o padrão.
Agrupar por duas colunas gera um grupo por combinação:
SELECT unidade_id, cargo, COUNT(*) FROM servidor
GROUP BY unidade_id, cargo ORDER BY unidade_id, cargo;
Saem seis grupos: (NULL, Analista) 1; (1, Analista) 1; (1, Tecnico) 1; (2, Analista) 2; (2, Tecnico) 1; (3, Tecnico) 1.
WHERE x HAVING
WHERE filtra linhas antes do agrupamento e não aceita função de agregação. HAVING filtra grupos depois do agrupamento e é onde se usa COUNT, SUM etc.
SELECT unidade_id, COUNT(*) AS n FROM servidor
GROUP BY unidade_id HAVING COUNT(*) >= 2 ORDER BY unidade_id;
Resultado: unidade 1 com 2 e unidade 2 com 3. Combinando os dois filtros:
SELECT unidade_id, COUNT(*) FROM servidor
WHERE cargo = 'Analista'
GROUP BY unidade_id HAVING COUNT(*) >= 2;
Primeiro o WHERE fica só com os quatro analistas; depois agrupa; depois o HAVING mantém grupos com 2 ou mais. Sobra apenas a unidade 2 (Carla e Diego), com contagem 2.
Ordem lógica de execução: FROM, WHERE, GROUP BY, HAVING, SELECT, ORDER BY.
Contar filhos com LEFT JOIN
Para contar quantos servidores cada unidade tem, incluindo as vazias:
SELECT u.nome, COUNT(s.id) AS qtd
FROM unidade u LEFT JOIN servidor s ON s.unidade_id = u.id
GROUP BY u.nome ORDER BY u.nome;
Resultado: Arquivo 1, Compras 3, Ouvidoria 0, Protocolo 2. Se trocar COUNT(s.id) por COUNT(*), a Ouvidoria passa a mostrar 1, porque a linha com NULL é uma linha. Esse é o erro mais comum de quem usa LEFT JOIN com agregação.
Erros comuns
- Colocar
COUNT(*) > 1noWHEREem vez doHAVING. - Dizer que
COUNT(coluna)conta nulos. - Esquecer que
AVGignora NULL e dividir pelo total de linhas. - Selecionar coluna não agrupada.
- Achar que
GROUP BYordena o resultado; sóORDER BYgarante ordem.
Fontes e atualização
Sem norma oficial brasileira sobre SQL, este guia segue o padrão da linguagem; os números foram obtidos executando as consultas em um banco de teste. Sistemas diferentes tratam colunas não agrupadas e a ordenação de NULL de modos distintos: confira o edital.
Próximos passos
- Veja o JOIN completo em SQL JOIN: INNER, LEFT, RIGHT, FULL e CROSS.
- Revise SELECT, WHERE, ORDER BY, LIKE e IN.
- Pratique a lógica numérica com estatística descritiva: média, mediana, moda e amplitude.