(Com diagramas, ilustrações e desafios adicionais)
Este artigo explora como o SQL filtra dados usando WHERE e HAVING, como funciona a agregação, e quando usar cada cláusula. Inclui diagramas, exemplos e desafios práticos.
A cláusula WHERE filtra linhas individuais antes de qualquer agrupamento ou agregação.
Linhas brutas da tabela
|
v
\+-----------+
| WHERE | \<-- filtra antes do agrupamento
\+-----------+
|
v
(Linhas filtradas)
SELECT product_name, price
FROM products
WHERE price > 300;
Agregação combina várias linhas em valores resumidos (SUM, COUNT, AVG etc.).
Linhas filtradas
|
v
+-------------+
| GROUP BY |
+-------------+
|
v
Resultados agregados
WHERE não pode filtrar valores agregados — por isso existe o HAVING.
Linhas brutas
|
v
+--------+
| WHERE |
+--------+
|
v
Linhas filtradas
|
v
+-----------+
| GROUP BY |
+-----------+
|
v
Linhas agregadas
|
v
+--------+
| HAVING | <-- filtra DEPOIS da agregação
+--------+
SELECT customer_id, SUM(amount) AS total_spent
FROM sales
GROUP BY customer_id
HAVING SUM(amount) > 150;
+------------------------------------+
| WHERE |
|------------------------------------|
| Filtra linhas individuais |
| Não usa agregações |
| Executa antes do GROUP BY |
+------------------------------------+
+------------------------------------+
| HAVING |
|------------------------------------|
| Filtra dados agregados |
| Usa COUNT, SUM etc |
| Executa após o GROUP BY |
+------------------------------------+
| Situação | WHERE | HAVING |
|---|---|---|
| Filtrar linhas por valores brutos | ✔ | ❌ |
| Filtrar grupos por valores agregados | ❌ | ✔ |
| Excluir linhas desnecessárias cedo | ✔ | ❌ |
| Usar COUNT(), SUM(), AVG() | ❌ | ✔ |
Tabela: orders(customer_id, order_amount, status)
Tarefa: Mostrar clientes que:
SELECT customer_id,
COUNT(*) AS num_orders,
SUM(order_amount) AS total_spent
FROM orders
WHERE status = 'Completed'
GROUP BY customer_id
HAVING COUNT(*) > 3
AND SUM(order_amount) > 500;
Tabela: products(category, price)
Tarefa: Listar categorias cuja média de preços esteja entre R$ 200 e R$ 500.
SELECT category, AVG(price) AS avg_price
FROM products
GROUP BY category
HAVING AVG(price) BETWEEN 200 AND 500;
Tabela: sales(store, amount, date)
Tarefa: Exibir lojas que tiveram pelo menos 10 vendas acima de R$ 50 durante janeiro.
SELECT store,
COUNT(*) AS count_sales
FROM sales
WHERE amount > 50
AND date BETWEEN '2025-01-01' AND '2025-01-31'
GROUP BY store
HAVING COUNT(*) >= 10;