(+351) 21 24 10006  ·  info@bconcepts.pt
Carnaxide, Lisboa

Como implementar SCD Tipo 2 em ETL: passo a passo

João Barros 06 de July de 2026 5 min de leitura

Guardar o histórico das dimensões é um dos problemas clássicos de qualquer data warehouse: quando a morada de um cliente muda, queres saber qual era o valor antigo e qual é o novo, sem apagar nada. A técnica que resolve isto chama-se SCD Tipo 2 (Slowly Changing Dimension) e vais aprender a implementá-la num pipeline ETL, passo a passo e com exemplos simples em SQL.

Pré-requisitos

  • Uma base de dados relacional (SQL Server, PostgreSQL, MySQL ou equivalente) onde possas criar tabelas.
  • Conhecimentos básicos de SQL: SELECT, INSERT e UPDATE.
  • Uma origem com os dados atuais dos clientes — o sistema operacional ou um ficheiro que carregas para uma área de staging.

Passo 1: Desenhar a dimensão com colunas de histórico

A ideia central do SCD Tipo 2 é simples: em vez de sobrescrever um valor que mudou, guardas uma nova linha e mantens a antiga. Para isso, a tabela de dimensão precisa de três colunas de controlo além dos atributos normais — uma data de início de validade, uma data de fim e um indicador que diz qual é a versão em vigor.

CREATE TABLE dim_cliente (
    cliente_sk  INT IDENTITY(1,1) PRIMARY KEY,  -- chave substituta
    cliente_id  INT          NOT NULL,          -- chave de negócio
    nome        VARCHAR(100),
    cidade      VARCHAR(100),
    valido_de   DATE         NOT NULL,
    valido_ate  DATE         NULL,
    ativo       BIT          NOT NULL DEFAULT 1
);

Repara na diferença entre as duas chaves. A surrogate key (cliente_sk) é única para cada versão e serve de ligação às tabelas de factos. A chave de negócio (cliente_id) identifica o cliente real, que ao longo do tempo pode ter várias linhas — uma por cada mudança.

Passo 2: Trazer os dados atuais para staging

Um bom pipeline ETL nunca compara diretamente com o sistema de origem. Em vez disso, copia o retrato atual dos dados para uma tabela de staging e trabalha a partir daí. Assim isolas a transformação e podes voltar a correr o processo sem sobrecarregar a origem.

CREATE TABLE stg_cliente (
    cliente_id INT,
    nome       VARCHAR(100),
    cidade     VARCHAR(100)
);
-- a extracao (E do ETL) preenche esta tabela com o estado de hoje

Passo 3: Detetar o que mudou

Agora comparas cada cliente da staging com a sua versão ativa na dimensão. Se um atributo relevante for diferente — por exemplo, a cidade — então esse cliente mudou e a sua versão atual tem de ser substituída.

SELECT s.cliente_id, s.nome, s.cidade
FROM   stg_cliente AS s
JOIN   dim_cliente AS d
       ON  d.cliente_id = s.cliente_id
       AND d.ativo = 1
WHERE  s.cidade <> d.cidade
   OR  s.nome   <> d.nome;

O JOIN por ativo = 1 garante que comparas apenas com a versão em vigor, ignorando as linhas históricas já fechadas. O operador <> (diferente) devolve só os registos que realmente mudaram.

Passo 4: Fechar as versões antigas

Para cada cliente alterado, marca a versão ativa como terminada: preenche a data de fim e coloca o indicador ativo a 0. Este "fecho suave" é o coração do SCD Tipo 2 — nunca apagas a linha, apenas dizes que deixou de estar em vigor.

UPDATE d
SET    d.valido_ate = CAST(GETDATE() AS DATE),
       d.ativo      = 0
FROM   dim_cliente AS d
JOIN   stg_cliente AS s
       ON  d.cliente_id = s.cliente_id
       AND d.ativo = 1
WHERE  s.cidade <> d.cidade
   OR  s.nome   <> d.nome;
Dica: usa sempre a mesma data (por exemplo, a data de execução do pipeline) para o fim de uma versão e o início da seguinte. Assim não ficam "buracos" na linha do tempo.

Passo 5: Inserir as novas versões

Falta inserir uma linha nova para cada cliente que já não tem versão ativa. E aqui está a parte elegante: como o Passo 4 acabou de fechar as versões alteradas, tanto os clientes novos como os alterados ficam agora sem nenhuma linha com ativo = 1. Um único INSERT trata os dois casos.

INSERT INTO dim_cliente (cliente_id, nome, cidade, valido_de, valido_ate, ativo)
SELECT s.cliente_id, s.nome, s.cidade, CAST(GETDATE() AS DATE), NULL, 1
FROM   stg_cliente AS s
LEFT JOIN dim_cliente AS d
       ON  d.cliente_id = s.cliente_id
       AND d.ativo = 1
WHERE  d.cliente_sk IS NULL;

A ordem é obrigatória: primeiro fechar (Passo 4), depois inserir (Passo 5). Se inverteres, arriscas ter duas versões ativas do mesmo cliente ao mesmo tempo — e o histórico deixa de fazer sentido.

Verificar o resultado

Para confirmar que ficou tudo bem, consulta um cliente que saibas que mudou. Deves ver duas linhas: a antiga, já com valido_ate preenchido e ativo = 0, e a nova, ainda aberta e ativa.

SELECT cliente_id, cidade, valido_de, valido_ate, ativo
FROM   dim_cliente
WHERE  cliente_id = 42
ORDER  BY valido_de;

A regra de ouro para validar um SCD Tipo 2: cada cliente_id deve ter exatamente uma linha com ativo = 1. Se aparecerem duas, algo correu mal na ordem dos passos.

Conclusão

Acabaste de construir uma dimensão SCD Tipo 2 completa — preparaste a tabela, detetaste as alterações, fechaste as versões antigas e inseriste as novas, sem perder um único dado histórico. O passo seguinte é juntar os Passos 4 e 5 numa só transação (para nunca ficarem a meio) e agendar todo o processo no teu orquestrador, seja o Azure Data Factory, o dbt ou um simples job de SQL. Antes de avançares, fica com esta pergunta: dos atributos da tua dimensão, quais precisam mesmo de histórico — e quais podes simplesmente sobrescrever com um SCD Tipo 1?