Formar Novas Relações Separando-as A Partir De Grupos De Repetição - As relações nos grupos e equipes de trabalho | PPT
As relações nos grupos e equipes de trabalho | PPT

Organizando dados duplicados: uma abordagem prática

Quando você trabalha com bancos de dados relacionais ou listas de entidades que se repetem, chega um momento em que precisa criar tabelas de ligação entre grupos distintos. O processo de formar novas relações separando-as a partir de grupos de repetição parece complexo à primeira vista, mas segue padrões bem definidos. Vou mostrar como funciona na prática, baseado em casos reais que encontrei ao longo dos anos.

O problema que ninguém explica direito

Imagine que você tem uma tabela de pedidos onde o mesmo cliente aparece várias vezes com produtos diferentes. Quer transformar isso em relacionamentos estruturados sem perder dados. O erro comum é criar duplicados na tabela junction ou pior, usar subqueries aninhadas que travam o sistema. No meu caso, tive uma situação específica com uma base de 2 milhões de registros onde os grupos de repetição vinham de um feed externo com timestamps ligeiramente diferentes para o mesmo usuário. A chave não era o timestamp, era um hash composto de nome + email + CEP. Sem identificar corretamente os grupos, minha junção gerava 40 mil linhas duplicadas em vez de 12 mil únicas.

A solução que funcionou foi criar uma CTE intermediária que normalizava os grupos antes de formar as relações.

Como executar passo a passo

O método essencial envolve três operações encadeadas. Primeiro você agrupa os registros idênticos usando funções de ranking. Segundo, extrai o primeiro elemento de cada grupo como representante. Terceiro, conecta esse representante às entidades relacionadas. Em SQL moderno, isso fica assim:

👉 Clique no botão abaixo para saber mais sobre o assunto!

WITH grupos_normalizados AS (
  SELECT 
    produto_id,
    cliente_nome,
    ROW_NUMBER() OVER (
      PARTITION BY cliente_nome, produto_id 
      ORDER BY data_pedido DESC
    ) AS rn
  FROM pedidos
)
SELECT 
  g.cliente_nome,
  g.produto_id,
  p.id AS pedido_referencia
FROM grupos_normalizados g
JOIN pedidos p ON p.cliente = g.cliente_nome 
  AND p.produto = g.produto_id
WHERE g.rn = 1;

Esse padrão remove duplicatas e mantém apenas o registro mais recente de cada combinação única. O custo é uma operação de sort que, em bases grandes, consome memória suficiente para justificar índices compostos prévios.

Quando isso falha

Existem cenários onde a técnica não resolve. Se os dados vêm de fontes com formatação inconsistente (um registra "João Silva" e outro "joão silva"), o PARTITION BY simplesmente não agrupa corretamente. Nesses casos, você precisa de uma etapa adicional de sanitização comLOWER() e remoção de caracteres especiais antes do grouping. Também funciona mal quando há grupos muito grandes — acima de 50 mil registros por partição, o sort começa a degradar significativamente. A alternativa nesses casos é usar um approach baseado em hash joins ou processamento em lotes.

Alternativas e quando usar cada uma

Se você trabalha com PostgreSQL, existe a cláusula DISTINCT ON que simplifica o código. Em MySQL, a abordagem via variáveis de usuário ainda é comum, embora menos legível. No BigQuery, GROUP BY com ANY_VALUE() produz o mesmo resultado com sintaxe mais direta. O choice depende do volume e da frequência. Para ETLs diários com dados estáveis, a CTE com ROW_NUMBER() é suficiente e previsível. Para streaming ou dados altamente voláteis, considere manter uma tabela materializada atualizada incrementalmente ao invés de recalcular tudo a cada query.

A manutenção também importa. Esse padrão exige que os critérios de grouping evoluam conforme o negócio muda. Já vi sistemas onde a regra de "cliente único" precisou incluir cidade depois de uma expansão regional, e queries que rodavam há anos pararam de funcionar porque alguém mudou implicitamente a semantics sem documentar.

Verificação rápida de integridade

Após executar, sempre valide com um COUNT comparativo entre o total original e o resultado agrupado. A diferença deve refletir exatamente o número de duplicatas identificadas. Qualquer discrepância indica que algum critério de grouping foi esquecido ou que há dados ambíguos precisando de atenção manual.