Filtrando Grupos com HAVING
Lição 4.3 · Tempo de leitura: ~7 minutos · Tarefas para praticar ↓
Quando você usa GROUP BY com agregações, frequentemente precisa filtrar grupos por seus resultados agregados. HAVING é o operador para filtrar grupos, assim como WHERE filtra linhas individuais. Nesta lição, você aprenderá as diferenças entre WHERE e HAVING, sintaxe e exemplos práticos com Sakila. Ao final, usará HAVING com confiança para análise profunda de dados.
Nas lições anteriores, você aprendeu GROUP BY para agrupar dados e aplicar agregações. Agora vem o próximo passo: filtrar os próprios grupos por condições em valores agregados.
HAVING faz isso permitindo condições após agrupamento.
100 mantém 395 de 599 clientes" width="100%">
WHERE vs HAVING
- WHERE filtra linhas antes do agrupamento
- HAVING filtra grupos após agregação
SELECT coluna1, COUNT(*) AS cnt
FROM tabela
WHERE coluna1 > 100 -- filtrar ANTES do agrupamento
GROUP BY coluna1
HAVING COUNT(*) > 10; -- filtrar APÓS o agrupamento
Sintaxe do HAVING
Estrutura básica:
SELECT coluna1, FUNCAO_AGG(coluna2)
FROM tabela
GROUP BY coluna1
HAVING condicao;
A condição em HAVING normalmente envolve uma função de agregação.
Exemplos com Uma Condição
Clientes com pagamentos totais acima de 100
SELECT customer_id, SUM(amount) AS total_paid
FROM payment
GROUP BY customer_id
HAVING SUM(amount) > 100;
Resultado: apenas clientes cujos pagamentos totais excedem 100.
Funcionários que processaram mais de 50 pagamentos
SELECT staff_id, COUNT(*) AS payments_count
FROM payment
GROUP BY staff_id
HAVING COUNT(*) > 50;
Resultado: funcionários com mais de 50 pagamentos processados.
Clientes com pagamento médio >= 5
SELECT customer_id, AVG(amount) AS avg_payment
FROM payment
GROUP BY customer_id
HAVING AVG(amount) >= 5;
Resultado: clientes cuja média de pagamento é de pelo menos 5.
HAVING com Múltiplas Condições
Você pode combinar condições usando AND e OR:
SELECT staff_id, COUNT(*) AS cnt, SUM(amount) AS total
FROM payment
GROUP BY staff_id
HAVING COUNT(*) > 50 AND SUM(amount) > 500;
Resultado: funcionários com mais de 50 pagamentos E total acima de 500.
Com operador OR
SELECT customer_id, COUNT(*) AS rentals, SUM(amount) AS paid
FROM payment
GROUP BY customer_id
HAVING COUNT(*) > 100 OR SUM(amount) > 1000;
Resultado: clientes com mais de 100 pagamentos OU total acima de 1000.
Exemplos Práticos
Categorias de filmes com vendas acima de 2000
SELECT category_id, SUM(p.amount) AS total_sales
FROM payment p
JOIN rental r ON p.rental_id = r.rental_id
JOIN inventory i ON r.inventory_id = i.inventory_id
JOIN film_category fc ON i.film_id = fc.film_id
GROUP BY category_id
HAVING SUM(p.amount) > 2000;
Paises com mais de 20 clientes
SELECT country, COUNT(*) AS customers_count
FROM customer cu
JOIN address a ON cu.address_id = a.address_id
JOIN city ci ON a.city_id = ci.city_id
JOIN country co ON ci.country_id = co.country_id
GROUP BY country
HAVING COUNT(*) > 20;
Funcionários com receita diária acima de 500
SELECT staff_id, DATE(payment_date) AS pay_date, SUM(amount) AS daily_revenue
FROM payment
GROUP BY staff_id, DATE(payment_date)
HAVING SUM(amount) > 500;
Resultado: 56 linhas, cada par funcionário-dia em que o funcionário recebeu mais de 500.
Perguntas Frequentes
Por que não posso usar WHERE em vez de HAVING?
WHERE funciona antes do agrupamento, então não pode verificar funções de agregação. HAVING funciona após agrupamento e pode analisar resultados de agregação (COUNT, SUM, AVG, etc.).
Posso usar uma coluna não agregada em HAVING?
Sim, você pode usar uma coluna do GROUP BY, mas geralmente não é necessário. Por exemplo, HAVING customer_id > 100 funciona, mas é mais natural escrever isso em WHERE antes do agrupamento.
HAVING pode ser usado sem GROUP BY?
Tecnicamente em alguns SGBDs isso é possível, mas é impraticável pois HAVING foi projetado para filtrar grupos. Use WHERE para filtrar linhas individuais sem agrupamento.
Perguntas de Entrevista
O que e HAVING e como difere de WHERE?
HAVING filtra grupos após agregação, enquanto WHERE filtra linhas antes do agrupamento. WHERE não pode funcionar com funções de agregação, mas HAVING funciona apenas com elas.
Posso usar WHERE e HAVING juntos em uma consulta?
Sim, é até recomendado. WHERE filtra linhas antes do agrupamento e HAVING filtra grupos após. Por exemplo, WHERE amount > 10 GROUP BY customer_id HAVING SUM(amount) > 100 primeiro exclui pequenos pagamentos, depois agrupa e filtra grupos.
Qual e a ordem de execução: WHERE ou HAVING?
WHERE é aplicado primeiro (antes de GROUP BY), depois GROUP BY executa agrupamento, depois HAVING filtra grupos resultantes, e finalmente ORDER BY e LIMIT são aplicados.
Principais conclusões desta lição:
- HAVING filtra grupos após agregação, WHERE filtra linhas antes do agrupamento.
- HAVING é usado com funções de agregação (COUNT, SUM, AVG, MIN, MAX).
- Você pode combinar múltiplas condições em HAVING usando AND/OR.
- Frequentemente WHERE e HAVING trabalham juntos: WHERE exclui linhas indesejadas, HAVING filtra grupos.
- HAVING permite consultas analíticas profundas com filtragem no nível do grupo.