DEV Community

Yuri Peixinho
Yuri Peixinho

Posted on

SQL: Aggregate Queries

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|
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode
| categoria   | receita |
|-------------|---------|
| Eletrônicos | 8200.00 |
| Periféricos |  310.00 |
Enter fullscreen mode Exit fullscreen mode

É 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;
Enter fullscreen mode Exit fullscreen mode
| 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       |
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode
| cliente     | receita_total |
|-------------|---------------|
| Ana Lima    | 3580.00       |
| Bruno Melo  | 3650.00       |
| Carla Nunes | 2480.00       |
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode
| cliente     | receita |
|-------------|---------|
| Ana Lima    | 3500.00 |
| Bruno Melo  | 3500.00 |
| Carla Nunes | 2400.00 |
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)