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

Pular para o conteúdo
Daniel Santos

Wiki SQL

Deduplicação

Evento repetido é regra em dado bruto (reenvio, retry, reprocessamento). DISTINCT resolve a cópia exata; ROW_NUMBER resolve "a mais recente de cada chave".

Na tabela eventos, o e2 chegou duas vezes. Na camada bronze isso fica como chegou; a silver é onde ele vira um só.

SQL · SQLite
SELECT id_evento, COUNT(*) AS vezes
FROM eventos
GROUP BY id_evento
HAVING COUNT(*) > 1;

Saída

id_evento | vezes
--------- | -----
e2        | 2

Cópia exata: DISTINCT

SQL · SQLite
SELECT COUNT(*) AS brutos,
       (SELECT COUNT(*) FROM (SELECT DISTINCT * FROM eventos)) AS distintos
FROM eventos;

Saída

brutos | distintos
------ | ---------
7      | 6

Mesma chave, versões diferentes: ROW_NUMBER

Quando a "cópia" muda em algum campo (o status do pedido foi atualizado), DISTINCT não ajuda. A regra é de negócio: aqui, fica o último evento de cada pedido.

SQL · SQLite
WITH numerados AS (
  SELECT *, ROW_NUMBER() OVER (PARTITION BY pedido_id ORDER BY ts DESC, id_evento DESC) AS n
  FROM eventos
)
SELECT pedido_id, tipo AS ultimo_estado, ts
FROM numerados
WHERE n = 1
ORDER BY pedido_id;

Saída

pedido_id | ultimo_estado | ts
--------- | ------------- | -------------------
101       | pago          | 2024-06-01 09:05:00
102       | pago          | 2024-06-01 10:30:00
103       | cancelado     | 2024-06-02 11:20:00

O desempate (id_evento DESC) não é enfeite: sem ele, dois eventos com o mesmo ts fazem a escolha depender da ordem física dos dados, e o resultado muda entre execuções.

No PySpark

PySparkPrecisa de um cluster Spark: não roda aqui.
from pyspark.sql import Window, functions as F

eventos = spark.table("bronze.eventos")
unicos = eventos.dropDuplicates(["id_evento"])

ultimo = Window.partitionBy("pedido_id").orderBy(F.desc("ts"), F.desc("id_evento"))
estado_atual = (unicos
    .withColumn("n", F.row_number().over(ultimo))
    .where("n = 1")
    .drop("n"))
  • dropDuplicates(["id_evento"]) mantém uma linha por chave, sem dizer qual. Se importa qual, use a janela.
  • Em streaming, dropDuplicates guarda estado para sempre; use withWatermark para limitar quanto tempo um evento repetido ainda é reconhecido.

Fontes

Conhecimento compartilhado pela Genesis Innovation.