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

Funcoes de Agregacao

COUNT, SUM, AVG, MIN e MAX

O que sao funcoes de agregacao?

Funcoes de agregacao pegam varias linhas e retornam um unico valor. Em vez de ver cada registro individualmente, voce obtem um resumo: quantos registros existem, qual a soma, a media, o menor ou o maior valor.

As cinco funcoes principais sao:

FuncaoO que faz
COUNTConta registros
SUMSoma valores
AVGCalcula a media
MINEncontra o menor valor
MAXEncontra o maior valor

COUNT -- contando registros

-- Quantos usuarios existem?
SELECT COUNT(*) FROM usuarios;
-- → 1523

-- Quantos usuarios tem telefone cadastrado?
SELECT COUNT(telefone) FROM usuarios;
-- → 1204 (ignora NULLs)

-- Quantos usuarios ativos existem?
SELECT COUNT(*) FROM usuarios WHERE status = 'ativo';
-- → 1389

-- Quantas cidades diferentes temos?
SELECT COUNT(DISTINCT cidade) FROM usuarios;
-- → 47

SUM -- somando valores

-- Valor total de todos os pedidos
SELECT SUM(valor_total) FROM pedidos;
-- → 458320.50

-- Valor total dos pedidos de janeiro
SELECT SUM(valor_total) FROM pedidos
WHERE data_criacao BETWEEN '2025-01-01' AND '2025-01-31';
-- → 52340.00

-- Total de itens em estoque
SELECT SUM(estoque) FROM produtos WHERE categoria = 'eletronicos';
-- → 3420

AVG -- calculando a media

-- Idade media dos usuarios
SELECT AVG(idade) FROM usuarios;
-- → 28.5

-- Preco medio dos produtos
SELECT AVG(preco) FROM produtos;
-- → 149.90

-- Nota media dos alunos aprovados
SELECT AVG(nota) FROM alunos WHERE nota >= 7;
-- → 8.3

-- Media arredondada com 2 casas decimais
SELECT ROUND(AVG(preco), 2) FROM produtos;
-- → 149.90

MIN e MAX -- encontrando extremos

-- Produto mais barato
SELECT MIN(preco) FROM produtos;
-- → 5.90

-- Produto mais caro
SELECT MAX(preco) FROM produtos;
-- → 4999.99

-- Usuario mais novo e mais velho
SELECT MIN(idade), MAX(idade) FROM usuarios;
-- → 16 | 72

-- Primeiro e ultimo cadastro
SELECT MIN(data_criacao), MAX(data_criacao) FROM usuarios;
-- → 2023-01-15 | 2025-03-28

-- MIN e MAX com strings (ordem alfabetica)
SELECT MIN(nome), MAX(nome) FROM usuarios;
-- → Abel | Zuleica

Combinando funcoes de agregacao

Voce pode usar varias funcoes na mesma query:

-- Resumo completo de produtos
SELECT
COUNT(*) AS total_produtos,
SUM(estoque) AS total_estoque,
ROUND(AVG(preco), 2) AS preco_medio,
MIN(preco) AS mais_barato,
MAX(preco) AS mais_caro
FROM produtos;
-- → 150 | 8430 | 149.90 | 5.90 | 4999.99

-- Resumo de pedidos do mes
SELECT
COUNT(*) AS total_pedidos,
SUM(valor_total) AS faturamento,
ROUND(AVG(valor_total), 2) AS ticket_medio,
MIN(valor_total) AS menor_pedido,
MAX(valor_total) AS maior_pedido
FROM pedidos
WHERE data_criacao >= '2025-03-01';

Combinando com WHERE

O WHERE filtra as linhas antes da agregacao rodar:

-- Media de preco apenas de eletronicos
SELECT AVG(preco) FROM produtos WHERE categoria = 'eletronicos';

-- Total vendido por um vendedor especifico
SELECT SUM(valor_total) FROM pedidos WHERE vendedor_id = 5;

-- Quantos pedidos acima de R$100
SELECT COUNT(*) FROM pedidos WHERE valor_total > 100;

-- Estatisticas apenas de usuarios ativos
SELECT
COUNT(*) AS ativos,
ROUND(AVG(idade), 1) AS idade_media,
MIN(data_criacao) AS primeiro_cadastro
FROM usuarios
WHERE status = 'ativo';

No Prisma

// COUNT
const total = await prisma.usuario.count()
const ativos = await prisma.usuario.count({ where: { status: 'ativo' } })

// Aggregate (SUM, AVG, MIN, MAX)
const stats = await prisma.produto.aggregate({
_sum: { preco: true, estoque: true },
_avg: { preco: true },
_min: { preco: true },
_max: { preco: true },
_count: true
})
// → stats._avg.preco = 149.90
// → stats._sum.estoque = 8430
// → stats._min.preco = 5.90
// → stats._count = 150

// Aggregate com WHERE
const eletronicos = await prisma.produto.aggregate({
_avg: { preco: true },
_count: true,
where: { categoria: 'eletronicos' }
})

// COUNT DISTINCT (via groupBy + contagem)
const cidadesUnicas = await prisma.usuario.groupBy({
by: ['cidade']
})
// → cidadesUnicas.length = numero de cidades distintas

No Drizzle

import { count, sum, avg, min, max } from 'drizzle-orm'

// COUNT
const [{ total }] = await db.select({ total: count() }).from(usuarios)

// COUNT com WHERE
const [{ ativos }] = await db.select({ ativos: count() }).from(usuarios)
.where(eq(usuarios.status, 'ativo'))

// Todas as agregacoes de uma vez
const [stats] = await db.select({
total: count(),
somaEstoque: sum(produtos.estoque),
precoMedio: avg(produtos.preco),
maisBarato: min(produtos.preco),
maisCaro: max(produtos.preco)
}).from(produtos)

// Com WHERE
const [eletronicos] = await db.select({
total: count(),
precoMedio: avg(produtos.preco)
}).from(produtos)
.where(eq(produtos.categoria, 'eletronicos'))

// COUNT DISTINCT
import { countDistinct } from 'drizzle-orm'
const [{ cidades }] = await db.select({
cidades: countDistinct(usuarios.cidade)
}).from(usuarios)

No Lucid (AdonisJS)

// COUNT
const total = await Usuario.query().count('* as total')
// → total[0].$extras.total = 1523

// Forma mais limpa com getCount
const ativos = await Usuario.query().where('status', 'ativo').getCount()
// → ativos = 1389

// SUM
const faturamento = await Pedido.query().sum('valor_total as total')
// → faturamento[0].$extras.total

// AVG
const media = await Produto.query().avg('preco as media')
// → media[0].$extras.media

// MIN e MAX
const extremos = await Produto.query()
.min('preco as mais_barato')
.max('preco as mais_caro')
// → extremos[0].$extras.mais_barato
// → extremos[0].$extras.mais_caro

// Combinando com WHERE
const statsEletronicos = await Produto.query()
.where('categoria', 'eletronicos')
.count('* as total')
.avg('preco as preco_medio')
.min('preco as mais_barato')
.max('preco as mais_caro')

// COUNT DISTINCT
const { default: Database } = await import('@adonisjs/lucid/services/db')
const cidades = await Database.from('usuarios').countDistinct('cidade as total')

Exercicios

  1. Escreva uma query que retorne o total de pedidos, o faturamento total e o ticket medio (valor medio por pedido).
  2. Encontre o produto mais caro e o mais barato de cada categoria (por enquanto, faca queries separadas -- GROUP BY vem na proxima aula).
  3. Calcule quantos usuarios se cadastraram em cada mes de 2025 (use WHERE para filtrar cada mes).
  4. Qual a diferenca entre COUNT(*) e COUNT(email) numa tabela onde alguns usuarios nao tem email?
  5. Implemente um dashboard de estatisticas usando Prisma: total de usuarios, total de pedidos, faturamento total e ticket medio.

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 é a diferença entre `COUNT(*)` e `COUNT(coluna)`?