Olha só, ainda não falamos sobre como filtrar grupos depois de aplicar agregações? Às vezes, não queremos todos os cursos — só aqueles onde tem mais de cem estudantes. Ou queremos ver só os departamentos onde o salário médio passa de 50.000. Hoje vamos conhecer a filtragem de dados agregados usando o HAVING.
Pra que serve o HAVING, se já temos o WHERE? Não dava pra colocar o WHERE depois do GROUP BY? :)
Não é tão simples! Primeiro, a ordem dos operadores em SQL é fixa e o WHERE é executado antes do GROUP BY.
Será que dá pra colocar ele depois do GROUP BY?
Também não! Muitas vezes a gente precisa filtrar as linhas da tabela antes de agrupar. Depois agrupa os dados filtrados. E aí, depois da agregação, joga fora alguns dados que não interessam.
Então, será que não dava só copiar o operador WHERE, chamar de HAVING e colocar depois do GROUP BY?
É isso mesmo que rola! :)
Diferença entre HAVING e WHERE
WHERE filtra as linhas antes da agregação.
Pensa que você tá escolhendo bolos pelo sabor: morango e chocolate você deixa, o resto vai pro lado. Essa é a função do WHERE.
HAVING filtra depois que os dados já foram agrupados e as funções agregadas fizeram sua mágica.
Por exemplo, você já agrupou os bolos por mesa, contou quantos tem em cada uma e agora quer deixar só as mesas com mais de três bolos.
Então, HAVING serve pra filtrar dados no nível dos grupos.
Sintaxe do HAVING
A sintaxe é quase igual ao WHERE, mas funciona um pouco diferente:
SELECT colunas, funções_agregadas
FROM tabela
GROUP BY colunas
HAVING condição;
Etapas de execução:
- Primeiro as linhas são filtradas pelo
WHERE. - Depois os dados são agrupados com o
GROUP BY. - As funções agregadas são aplicadas nos resultados dos grupos.
- Por fim, o resultado é filtrado com o
HAVING.
Exemplos de uso do HAVING
Exemplo 1: Filtrando cursos com muitos estudantes
Você quer saber quais cursos da faculdade têm mais de 100 estudantes. Suponha que temos a tabela students:
| id | name | faculty |
|---|---|---|
| 1 | Alice | Engineering |
| 2 | Bob | Engineering |
| 3 | Charlie | Arts |
| 4 | Daisy | Business |
| 5 | ... | ... |
Consulta:
SELECT faculty, COUNT(*) AS student_count
FROM students
GROUP BY faculty
HAVING COUNT(*) > 100;
O que tá rolando aqui:
- Primeiro a gente agrupa os estudantes pela coluna
facultyusando oGROUP BY. - Depois a função agregada
COUNT(*)conta quantos estudantes tem em cada curso. - Por fim, o
HAVINGelimina todos os cursos com 100 estudantes ou menos.
Resultado:
| faculty | student_count |
|---|---|
| Engineering | 150 |
| Arts | 120 |
Exemplo 2: Departamentos com salário médio alto
Você quer achar só os departamentos onde o salário médio dos funcionários passa de 50.000. Suponha que temos a tabela employees:
| id | name | department | salary |
|---|---|---|---|
| 1 | Alice | IT | 60000 |
| 2 | Bob | HR | 45000 |
| 3 | Charlie | IT | 70000 |
| 4 | Daisy | HR | 52000 |
| 5 | ... | ... | ... |
Consulta:
SELECT department, AVG(salary) AS avg_salary
FROM employees
GROUP BY department
HAVING AVG(salary) > 50000;
Resultado:
| department | avg_salary |
|---|---|
| IT | 65000 |
Repara: o HAVING trabalha com os resultados que foram calculados depois do GROUP BY.
Ordem de execução do WHERE, GROUP BY e HAVING
Filtrar com WHERE e HAVING acontece em etapas diferentes. Pra entender melhor a diferença, olha o passo a passo da consulta:
WHERE: filtragem das linhas.Nessa etapa, todas as linhas da tabela são processadas. Se a linha não passa no
WHERE, ela nem entra no resto do processo.GROUP BY: agrupamento das linhas.Depois de filtrar, as linhas são agrupadas pelos campos que você colocou no
GROUP BY.Funções agregadas:
As funções agregadas tipo
COUNT(),AVG(),SUM()etc. são aplicadas nos grupos.HAVING: filtragem dos grupos.Nessa etapa, só os resultados das agregações são processados. As condições do
HAVINGsó valem pros grupos.
Particularidades do HAVING
Particularidade 1: Trabalhando com agregados
A principal diferença do HAVING pro WHERE é que ele trabalha com funções agregadas. Por exemplo:
SELECT department, AVG(salary)
FROM employees
GROUP BY department
HAVING AVG(salary) > 50000;
Nessa consulta, não dá pra usar AVG(salary) dentro do WHERE, porque o WHERE roda antes da agregação. Uma consulta tipo:
SELECT department, AVG(salary)
FROM employees
WHERE AVG(salary) > 50000
GROUP BY department;
vai dar erro: aggregate functions are not allowed in WHERE.
Particularidade 2: Filtrando sem agrupar
Você pode usar o HAVING até sem um GROUP BY explícito. Nesse caso, a consulta é interpretada como se tivesse um grupo só — todos os registros:
SELECT AVG(salary) AS avg_salary
FROM employees
HAVING AVG(salary) > 50000;
Exemplo prático
Imagina que temos uma loja e uma tabela de vendas sales:
| id | product_id | sales_amount |
|---|---|---|
| 1 | 101 | 200.00 |
| 2 | 102 | 300.00 |
| 3 | 101 | 400.00 |
| 4 | 103 | 150.00 |
Consulta: achar produtos com volume total de vendas maior que 500.
SELECT product_id, SUM(sales_amount) AS total_sales
FROM sales
GROUP BY product_id
HAVING SUM(sales_amount) > 500;
Resultado:
| product_id | total_sales |
|---|---|
| 101 | 600.00 |
Erros comuns
Usar agregados no WHERE:
Por exemplo:
SELECT department, AVG(salary)
FROM employees
WHERE AVG(salary) > 50000
GROUP BY department;
Erro: não pode usar funções agregadas no WHERE.
Erros com NULL:
Se os dados têm NULL, a filtragem pode dar resultados estranhos. Por exemplo:
SELECT department, SUM(salary)
FROM employees
GROUP BY department
HAVING SUM(salary) > 0;
Se a coluna salary só tem NULL, o resultado pode ser zero ou vazio.
Parabéns! Agora você já consegue filtrar dados agregados de boa! Não esquece: HAVING é sua chave pra análise no nível dos grupos, onde o WHERE normal não dá conta.
GO TO FULL VERSION