Proposta de site feita pela Genesis Innovation · conteúdo do LinkedIn de Daniel Santos

Pular para o conteúdo
Daniel Santos

Wiki SQL

GROUP BY, HAVING e agregações

COUNT(*) conta linhas, COUNT(coluna) conta valores; HAVING filtra grupos; NULL vira um grupo.

Agregar é transformar muitas linhas em uma por grupo. As funções de agregação ignoram NULL, com uma exceção: COUNT(*), que conta linhas.

SQL · SQLite
SELECT COUNT(*) AS linhas,
       COUNT(valor) AS com_valor,
       SUM(valor) AS soma,
       AVG(valor) AS media
FROM pedidos;

Saída

linhas | com_valor | soma | media
------ | --------- | ---- | -----
10     | 9         | 3600 | 400

A média ignorou o pedido sem valor: é SUM(valor) / COUNT(valor), não dividido por todas as linhas. Se "sem valor" deveria contar como zero, diga isso com COALESCE(valor, 0).

HAVING filtra grupos

WHERE roda antes de agrupar; HAVING, depois. Filtro sobre o resultado de uma agregação só pode ir no HAVING.

SQL · SQLite
SELECT cliente_id, COUNT(*) AS pedidos, SUM(valor) AS total
FROM pedidos
WHERE status <> 'cancelado'
GROUP BY cliente_id
HAVING COUNT(*) >= 2
ORDER BY total DESC;

Saída

cliente_id | pedidos | total
---------- | ------- | -----
1          | 2       | 1130
2          | 2       | 1050
3          | 2       | 180

NULL é um grupo

Para o GROUP BY, todos os NULL caem no mesmo grupo (embora NULL = NULL não seja verdadeiro).

SQL · SQLite
SELECT cidade, COUNT(*) AS clientes
FROM clientes
GROUP BY cidade
ORDER BY clientes DESC, cidade;

Saída

cidade    | clientes
--------- | --------
São Paulo | 2
NULL      | 1
Campinas  | 1
Curitiba  | 1
Recife    | 1

COUNT(DISTINCT)

SQL · SQLite
SELECT COUNT(DISTINCT cliente_id) AS cliente_ids_distintos,
       COUNT(DISTINCT data) AS dias_com_venda
FROM pedidos;

Saída

cliente_ids_distintos | dias_com_venda
--------------------- | --------------
6                     | 5

São 6 ids e não 5 clientes de verdade: o 9 do pedido órfão entra na conta. COUNT(DISTINCT) não sabe se a chave existe na outra tabela; isso é trabalho de um JOIN ou de uma regra de qualidade.

  • Em grandes volumes, COUNT(DISTINCT) exato é caro; Spark e Databricks têm approx_count_distinct (HyperLogLog), com erro controlado.
  • Toda coluna do SELECT que não está numa agregação precisa estar no GROUP BY (o SQLite deixa passar, o padrão e o Spark não).

Fontes

Conhecimento compartilhado pela Genesis Innovation.