O problema: filtrar por um agregado
E se você só quiser as categorias com mais de 2 produtos, ou com um preço
médio acima de 100? Você não pode usar WHERE, porque WHERE olha linha a
linha, e nesse ponto o agregado do grupo ainda não existe.
É para isso que serve o HAVING: filtra grupos conforme o valor do seu agregado,
depois de aplicar GROUP BY.
SELECT categoria, COUNT(*) AS total
FROM produtos
GROUP BY categoria
HAVING COUNT(*) > 2;
WHERE vs HAVING (a diferença-chave)
| Cláusula | Filtra... | Quando atua | Pode usar agregados? |
|---|---|---|---|
WHERE |
linhas | antes de agrupar | Não |
HAVING |
grupos | depois de agrupar | Sim |
A ordem lógica de execução é:
FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY
Por isso você pode combinar as duas: WHERE descarta linhas individuais antes
de agrupar, e HAVING descarta grupos inteiros depois.
-- Apenas produtos com estoque, agrupados por categoria,
-- ficando com as categorias cujo preço médio supera 100
SELECT categoria, AVG(preco) AS preco_medio
FROM produtos
WHERE estoque > 0
GROUP BY categoria
HAVING AVG(preco) > 100
ORDER BY categoria;
Regra prática: se a condição pode ser avaliada olhando uma única linha, vai no
WHERE; se precisa do resultado do grupo, vai noHAVING.