Todo mundo gosta de falar de pipeline incremental como se bastasse escrever um MERGE elegante e seguir a vida. No mundo real, o problema costuma começar antes: lote repetido, registro atrasado, chave quebrada e regra de recência mal definida.
É por isso que muita carga incremental até roda todo dia, mas ninguém confia de verdade no resultado.
Se você quiser montar um pipeline pequeno com cara profissional, o ponto não é complexidade. É ordem. Um fluxo bom separa ingestão, tratamento, escrita e checagem final.
O desenho mínimo que já evita metade da dor
Para uma base incremental simples, quatro blocos bastam:
- staging bruta;
- staging tratada;
- escrita incremental;
- validação depois da carga.
Pode parecer básico, mas esse desenho já resolve duas coisas que quebram muita operação pequena: ele preserva rastreabilidade e deixa claro onde cada decisão aconteceu.
Comece pela staging bruta, não pela regra de negócio
A staging bruta recebe o lote como ele chegou. Sem heroísmo.
Se a API mandou registro repetido, campo vazio ou status estranho, isso precisa aparecer ali. A função dessa camada não é embelezar a origem. É guardar o material de entrada para que você consiga explicar depois por que a tabela final ficou de um jeito e não de outro.
Exemplo de colunas:
pedido_idcliente_idstatusvalorupdated_atcanal
Quando alguém pergunta “de onde saiu esse valor?”, a staging bruta é o primeiro lugar em que você deveria conseguir voltar.
A staging tratada é onde o pipeline vira raciocínio
É aqui que as CTEs fazem sentido. Não por estética, mas porque ajudam a separar perguntas.
WITH base AS (
SELECT
pedido_id,
cliente_id,
status,
valor,
updated_at,
COALESCE(canal, 'desconhecido') AS canal
FROM staging_pedidos_bruta
),
deduplicada AS (
SELECT *
FROM (
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY pedido_id
ORDER BY updated_at DESC
) AS rn
FROM base
) t
WHERE rn = 1
),
validada AS (
SELECT
pedido_id,
cliente_id,
status,
valor,
updated_at,
canal
FROM deduplicada
WHERE pedido_id IS NOT NULL
)
SELECT *
FROM validada;
Repare no que cada etapa responde:
basepadroniza o lote;deduplicadaescolhe qual versão de cada pedido sobrevive;validadaremove o que nem deveria entrar na escrita final.
Essa clareza vale mais do que uma query gigante que “faz tudo”.
Regra de recência precisa estar explícita
O ponto mais sensível de quase toda carga incremental é decidir quem vence quando a mesma chave aparece mais de uma vez.
No exemplo acima, a regra é simples: fica a linha com updated_at mais recente. Em outras bases, o critério pode ser versão, timestamp de ingestão ou um status prioritário. O importante é não deixar isso implícito.
Quando a regra de recência não está clara, o pipeline pode até parecer estável, mas basta um lote chegar fora de ordem para a tabela final começar a andar para trás.
O MERGE vem depois do trabalho importante
Com a staging tratada pronta, a escrita incremental fica mais honesta:
MERGE INTO pedidos_final AS destino
USING validada AS origem
ON destino.pedido_id = origem.pedido_id
WHEN MATCHED THEN
UPDATE SET
cliente_id = origem.cliente_id,
status = origem.status,
valor = origem.valor,
updated_at = origem.updated_at,
canal = origem.canal
WHEN NOT MATCHED THEN
INSERT (
pedido_id,
cliente_id,
status,
valor,
updated_at,
canal
)
VALUES (
origem.pedido_id,
origem.cliente_id,
origem.status,
origem.valor,
origem.updated_at,
origem.canal
);
O MERGE não salva pipeline ruim. Ele só aplica a decisão que você já deixou pronta antes.
Se a origem ainda está suja, a tabela final vai formalizar a sujeira com muito mais confiança.
Validação depois da carga não é um luxo
Esse é o trecho que mais some em projeto apressado. Não deveria.
Depois da escrita, pelo menos estas checagens precisam existir:
Duplicidade por chave
SELECT pedido_id, COUNT(*)
FROM pedidos_final
GROUP BY 1
HAVING COUNT(*) > 1;
Se a tabela é uma linha por pedido, o retorno esperado é zero.
Volume total e variação suspeita
Compare o tamanho da tabela final com o histórico recente e com o tamanho do lote.
Nulos em colunas críticas
SELECT
AVG(CASE WHEN cliente_id IS NULL THEN 1 ELSE 0 END) AS pct_cliente_nulo
FROM pedidos_final;
Métrica de controle
Some uma métrica relevante, como valor total ou quantidade de pedidos únicos, e veja se ela continua fazendo sentido depois da carga.
O erro mais comum não é técnico. É de desenho
Muita gente complica cedo demais com ferramenta, YAML, DAG, job e nomenclatura sofisticada. Tudo isso pode entrar depois. Antes disso, o que define maturidade é outra coisa:
- separar entrada de decisão;
- deduplicar com critério claro;
- preservar chave e granularidade;
- validar a tabela final.
Se esse desenho estiver firme, você já está pensando como alguém que constrói base para outras pessoas usarem, e não apenas como alguém que escreveu uma query funcional.
O mínimo profissional
Se eu tivesse que resumir o padrão em uma linha, seria esta:
staging bruta -> staging tratada -> escrita incremental -> validação
Não é sofisticado. Mas é o suficiente para um pipeline pequeno não virar bagunça na primeira semana em que o lote chega fora do esperado.
