Agregação e Agrupamento
Aula 3 de 8
Funções de Agregação
SELECT
COUNT(*) AS total_linhas,
COUNT(email) AS emails_nao_nulos, -- ignora NULL
COUNT(DISTINCT cidade) AS cidades_unicas,
SUM(salario) AS folha_pagamento,
AVG(salario) AS media_salarial,
MIN(salario) AS menor_salario,
MAX(salario) AS maior_salario
FROM funcionarios;
Comportamento com NULL
-- AVG ignora NULL (soma/não-nulos)
-- SUM ignora NULL (NULL + 10 = NULL? Não, SUM trata NULL como 0)
-- COUNT(coluna) ignora NULL
-- COUNT(*) conta linhas (inclui NULLs)
-- Tratar NULL explicitamente
SELECT AVG(COALESCE(comissao, 0)) FROM funcionarios;
GROUP BY
-- Agrupar por departamento
SELECT
departamento,
COUNT(*) AS funcionarios,
AVG(salario)::DECIMAL(10,2) AS media_salarial,
SUM(salario) AS total
FROM funcionarios
GROUP BY departamento
ORDER BY media_salarial DESC;
-- Múltiplas colunas
SELECT
departamento,
cargo,
COUNT(*) AS qtd,
AVG(salario) AS media
FROM funcionarios
GROUP BY departamento, cargo
ORDER BY departamento, cargo;
HAVING — Filtro de Grupos
-- WHERE filta linhas, HAVING filta grupos
SELECT
cliente_id,
COUNT(*) AS total_pedidos,
SUM(total) AS total_gasto
FROM pedidos
WHERE data_pedido >= '2024-01-01'
GROUP BY cliente_id
HAVING COUNT(*) >= 5 AND SUM(total) > 1000
ORDER BY total_gasto DESC;
Window Functions
-- ROW_NUMBER: numeração dentro de partição
SELECT
nome,
departamento,
salario,
ROW_NUMBER() OVER (PARTITION BY departamento ORDER BY salario DESC) AS rank_salario
FROM funcionarios;
-- RANK vs DENSE_RANK vs ROW_NUMBER
SELECT
nome, salario,
ROW_NUMBER() OVER (ORDER BY salario DESC) AS "rn",
RANK() OVER (ORDER BY salario DESC) AS "rank",
DENSE_RANK() OVER (ORDER BY salario DESC) AS "dense"
FROM funcionarios;
-- ROW_NUMBER: 1, 2, 3, 4 (sem empates)
-- RANK: 1, 1, 3, 4 (empate pula)
-- DENSE_RANK: 1, 1, 2, 3 (empate não pula)
-- LAG/LEAD (linha anterior/próxima)
SELECT
data,
valor,
LAG(valor) OVER (ORDER BY data) AS valor_anterior,
valor - LAG(valor) OVER (ORDER BY data) AS variacao,
AVG(valor) OVER (ORDER BY data ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS media_7dias
FROM cotacoes;
-- SUM acumulado
SELECT
mes,
receita,
SUM(receita) OVER (ORDER BY mes) AS receita_acumulada
FROM receitas_mensais;
-- FIRST_VALUE / LAST_VALUE
SELECT
produto,
preco,
FIRST_VALUE(produto) OVER (ORDER BY preco DESC) AS mais_caro
FROM produtos;
Funções Estatísticas
-- PERCENTILE (mediana, quartis)
SELECT
PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY salario) AS mediana,
PERCENTILE_CONT(0.25) WITHIN GROUP (ORDER BY salario) AS q1,
PERCENTILE_CONT(0.75) WITHIN GROUP (ORDER BY salario) AS q3
FROM funcionarios;
-- Moda (valor mais frequente)
SELECT salario, COUNT(*) AS freq
FROM funcionarios
GROUP BY salario
ORDER BY freq DESC
LIMIT 1;
Lab: Análise de Vendas
SELECT
DATE_TRUNC('month', data_pedido) AS mes,
COUNT(DISTINCT cliente_id) AS clientes_ativos,
COUNT(id) AS pedidos,
SUM(total) AS receita,
AVG(total) AS ticket_medio,
LAG(SUM(total)) OVER (ORDER BY DATE_TRUNC('month', data_pedido)) AS receita_mes_anterior,
SUM(total) - LAG(SUM(total)) OVER (ORDER BY DATE_TRUNC('month', data_pedido)) AS variacao
FROM pedidos
GROUP BY mes
ORDER BY mes;
Funções de agregação + GROUP BY = análise de dados. Window Functions (OVER) para análises avançadas sem perder detalhes. HAVING filtra grupos como WHERE filtra linhas.