Pular para o conteúdo

A primeira escola especializada em tecnologia do Alto Solimões, com corpo técnico formado na área.

Modulo 3: Consultas Avancadas

GROUP BY e HAVING

Agrupando resultados e filtrando grupos

O que e GROUP BY?

Ate agora, todas as consultas retornavam linhas individuais. Mas e quando voce quer respostas como "quantos alunos tem em cada cidade?" ou "qual a media de nota por turma?"? E ai que entra o GROUP BY: ele junta linhas que tem o mesmo valor em uma coluna e permite usar funcoes de agregacao em cada grupo.

Funcoes de agregacao

Antes de agrupar, voce precisa conhecer as funcoes que trabalham com grupos:

FuncaoO que faz
COUNT(*)Conta quantas linhas tem no grupo
SUM()Soma os valores da coluna
AVG()Calcula a media dos valores
MIN()Retorna o menor valor
MAX()Retorna o maior valor
-- Sem GROUP BY, a funcao age em TODAS as linhas
SELECT COUNT(*) AS total FROM alunos;
-- → 150

SELECT AVG(nota) AS media_geral FROM alunos;
-- → 7.45

GROUP BY na pratica

Imagine a tabela alunos:

idnomecidadenota
1AnaSao Paulo8.5
2BrunoCuritiba7.0
3CarlaSao Paulo9.0
4DiegoCuritiba6.5
5ElenaBelo Horizonte8.0
SELECT cidade, COUNT(*) AS total_alunos
FROM alunos
GROUP BY cidade;

Resultado:

cidadetotal_alunos
Sao Paulo2
Curitiba2
Belo Horizonte1
-- Media de nota por cidade
SELECT cidade, AVG(nota) AS media_nota
FROM alunos
GROUP BY cidade;
cidademedia_nota
Sao Paulo8.75
Curitiba6.75
Belo Horizonte8.00

WHERE vs HAVING

Essa e uma das confusoes mais comuns em SQL. A regra e simples:

  • WHERE filtra linhas ANTES do agrupamento
  • HAVING filtra grupos DEPOIS do agrupamento
-- WHERE: filtra linhas antes de agrupar
-- So considera alunos com nota >= 7
SELECT cidade, COUNT(*) AS total_aprovados
FROM alunos
WHERE nota >= 7
GROUP BY cidade;
cidadetotal_aprovados
Sao Paulo2
Curitiba1
Belo Horizonte1
-- HAVING: filtra grupos depois de agrupar
-- So mostra cidades com mais de 1 aluno
SELECT cidade, COUNT(*) AS total_alunos
FROM alunos
GROUP BY cidade
HAVING COUNT(*) > 1;
cidadetotal_alunos
Sao Paulo2
Curitiba2

Combinando WHERE e HAVING

Voce pode usar os dois juntos. O WHERE filtra primeiro, depois o GROUP BY agrupa, e o HAVING filtra os grupos:

-- Cidades com mais de 1 aluno aprovado (nota >= 7)
SELECT cidade, COUNT(*) AS aprovados
FROM alunos
WHERE nota >= 7
GROUP BY cidade
HAVING COUNT(*) > 1;

A ordem de execucao no banco e: FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY.

GROUP BY com ORDER BY

Voce pode ordenar o resultado agrupado:

SELECT cidade, COUNT(*) AS total
FROM alunos
GROUP BY cidade
ORDER BY total DESC;

GROUP BY nos ORMs

Prisma

const alunosPorCidade = await prisma.aluno.groupBy({
by: ['cidade'],
_count: { id: true },
_avg: { nota: true },
having: {
nota: { _avg: { gt: 7 } }
}
})

Drizzle

import { sql, count, avg } from 'drizzle-orm'

const resultado = await db
.select({
cidade: alunos.cidade,
total: count(),
media: avg(alunos.nota)
})
.from(alunos)
.groupBy(alunos.cidade)
.having(sql`count(*) > 1`)

Lucid (AdonisJS)

const resultado = await Aluno
.query()
.select('cidade')
.count('* as total')
.avg('nota as media_nota')
.groupBy('cidade')
.having('count(*)', '>', 1)

Exercicios

  1. Escreva uma consulta que retorne a quantidade de alunos por cidade, ordenada da maior para a menor quantidade.
  2. Escreva uma consulta que retorne a maior nota por cidade.
  3. Escreva uma consulta que mostre apenas cidades onde a media de notas e maior que 7.
  4. Usando WHERE e HAVING juntos, retorne cidades com mais de 2 alunos que tem nota acima de 6.

Referencias

Testa o que você leu

5 perguntas sobre esta aula. Errar aqui não custa nada - a explicação vem junto da correção.

Pergunta 1 de 5
Qual cláusula agrupa linhas que têm o mesmo valor numa coluna?