Introdução
Consultas individuais respondem perguntas como "qual o email do cliente 42?". Mas as perguntas mais valiosas em qualquer sistema são de outro tipo: "qual o produto mais vendido?", "qual a receita média por pedido?", "quantos clientes se cadastraram esse mês?". Para responder isso, o SQL oferece as funções de agregação — operações que recebem um conjunto de linhas e devolvem um único valor resumido.
Para os exemplos a seguir, considere esta tabela:
pedidos:
| id | cliente | produto | categoria | quantidade | valor |
|----|------------|-------------|--------------|------------|--------|
| 1 | Ana Lima | Notebook | Eletrônicos | 1 | 3500.00|
| 2 | Ana Lima | Mouse | Periféricos | 2 | 80.00|
| 3 | Bruno Melo | Teclado | Periféricos | 1 | 150.00|
| 4 | Bruno Melo | Notebook | Eletrônicos | 1 | 3500.00|
| 5 | Carla Nunes| Monitor | Eletrônicos | 2 | 1200.00|
| 6 | Carla Nunes| Mouse | Periféricos | 1 | 80.00|
As Funções de Agregação
COUNT
Conta o número de linhas — ou de valores não nulos em uma coluna específica.
-- Total de pedidos
SELECT COUNT(*)AS total_pedidosFROM pedidos;
-- Resultado: 6
-- Clientes distintos que fizeram pedidos
SELECT COUNT(DISTINCT cliente) AS clientes_unicosFROM pedidos;
-- Resultado: 3
COUNT(*) conta todas as linhas, incluindo as que têm nulos. COUNT(coluna) conta apenas as linhas onde aquela coluna não é nula. COUNT(DISTINCT coluna) conta valores únicos — útil para saber quantos clientes, produtos ou categorias distintos aparecem no resultado.
SUM
Soma os valores de uma coluna numérica.
-- Receita total
SELECT SUM(valor) AS receita_total FROM pedidos;
-- Resultado: 8510.00
-- Total de itens vendidos
SELECT SUM(quantidade) AS itens_vendidos FROM pedidos;
-- Resultado: 8
AVG
Calcula a média aritmética dos valores.
-- Valor médio por pedido
SELECT AVG(valor) AS ticket_medio FROM pedidos;
-- Resultado: 1418.33
AVG ignora valores nulos automaticamente — calcula a média apenas sobre os registros que têm valor preenchido naquela coluna.
MIN e MAX
Retornam o menor e o maior valor de uma coluna, respectivamente. Funcionam com números, datas e texto.
SELECT
MIN(valor) AS pedido_minimo,
MAX(valor) AS pedido_maximo
FROM pedidos;
-- Resultado: 80.00 | 3500.00
Com datas, MIN retorna a data mais antiga e MAX a mais recente — útil para saber o primeiro e o último evento de um conjunto.
GROUP BY
Funções de agregação sem GROUP BY resumem a tabela inteira em uma linha. Com GROUP BY, elas resumem por grupo — calculando um resultado para cada valor distinto da coluna agrupada.
-- Receita total por categoria
SELECT
categoria,
SUM(valor) AS receita
FROM pedidos
GROUP BY categoria;
| categoria | receita |
|-------------|---------|
| Eletrônicos | 8200.00 |
| Periféricos | 310.00 |
É possível agrupar por múltiplas colunas:
-- Receita por cliente e categoria
SELECT
cliente,
categoria,
SUM(valor) AS receita,
COUNT(*) AS pedidos
FROM pedidos
GROUP BY cliente, categoria
ORDER BY cliente, receitaDESC;
| cliente | categoria | receita | pedidos |
|-------------|-------------|---------|---------|
| Ana Lima | Eletrônicos | 3500.00 | 1 |
| Ana Lima | Periféricos | 160.00 | 1 |
| Bruno Melo | Eletrônicos | 3500.00 | 1 |
| Bruno Melo | Periféricos | 150.00 | 1 |
| Carla Nunes | Eletrônicos | 2400.00 | 1 |
| Carla Nunes | Periféricos | 80.00 | 1 |
Uma regra importante: toda coluna no SELECT que não é uma função de agregação precisa estar no GROUP BY. O banco precisa saber como agrupar — se você seleciona cliente e categoria mas agrega por apenas um, ele não sabe qual valor exibir para o outro.
HAVING
WHERE filtra linhas antes da agregação. HAVING filtra grupos depois da agregação. São complementares, não concorrentes.
-- Apenas clientes com receita total acima de 1000
SELECT
cliente,
SUM(valor) AS receita_total
FROM pedidos
GROUP BY cliente
HAVING SUM(valor)> 1000;
| cliente | receita_total |
|-------------|---------------|
| Ana Lima | 3580.00 |
| Bruno Melo | 3650.00 |
| Carla Nunes | 2480.00 |
A diferença entre WHERE e HAVING fica clara quando os dois aparecem juntos:
-- Receita por cliente, considerando apenas pedidos de Eletrônicos,
-- e mostrando apenas quem passou de 2000
SELECT
cliente,
SUM(valor)AS receita
FROM pedidos
WHERE categoria = 'Eletrônicos' -- filtra linhas antes de agrupar
GROUP BY cliente
HAVING SUM(valor) > 2000;-- filtra grupos depois de agregar
| cliente | receita |
|-------------|---------|
| Ana Lima | 3500.00 |
| Bruno Melo | 3500.00 |
| Carla Nunes | 2400.00 |
Carla passou porque seus R$ 2.400 em Eletrônicos superam o limite de R$ 2.000. Se o limite fosse R$ 3.000, apenas Ana e Bruno apareceriam.
A Ordem de Execução
Entender a ordem em que o SQL processa as cláusulas explica por que HAVING existe como cláusula separada do WHERE:
1. FROM → identifica a tabela
2. WHERE → filtra as linhas brutas
3. GROUP BY → agrupa as linhas restantes
4. HAVING → filtra os grupos formados
5. SELECT → calcula as expressões e funções
6. ORDER BY → ordena o resultado final
7. LIMIT → recorta a quantidade retornada
WHERE atua antes da agregação existir — por isso não é possível usar uma função de agregação dentro do WHERE. Tentar WHERE SUM(valor) > 1000 resulta em erro. Para filtrar por resultado de agregação, o lugar certo é sempre o HAVING.
Top comments (0)