Como implementar SCD Tipo 2 em ELT: passo a passo
Guardar o histórico de alterações de um cliente — como uma mudança de morada ou de segmento — é essencial para análises fiáveis ao longo do tempo. O padrão SCD Tipo 2 (Slowly Changing Dimension) resolve isto: cria uma nova versão do registo sempre que um atributo muda, em vez de substituir o valor antigo. Num fluxo ELT, os dados chegam primeiro à camada de staging e são transformados com SQL já dentro do data warehouse.
Pré-requisitos
- Acesso a um data warehouse com SQL (SQL Server, Azure Synapse, Snowflake, Databricks ou BigQuery).
- Uma tabela de staging com os dados atuais da origem (por exemplo,
stg_clientes). - Noções básicas de SQL:
INSERT,UPDATEeJOIN. - Permissões para criar e alterar tabelas no destino.
Passo 1: Perceber o que é uma dimensão SCD Tipo 2
Uma dimensão SCD Tipo 2 mantém várias linhas para a mesma entidade — por exemplo, um cliente — uma por cada período em que os seus dados foram válidos. Três colunas de controlo tornam isto possível: valid_from (início da validade), valid_to (fim da validade) e is_current (marca a versão ativa). Assim, uma consulta consegue saber qual era o segmento de um cliente em qualquer data do passado, algo impossível se apenas guardássemos o valor mais recente.
Passo 2: Criar a tabela de dimensão com colunas de histórico
Além dos atributos do negócio (nome, segmento), a tabela final precisa de uma chave substituta (surrogate key) e das três colunas de controlo. A coluna cliente_id guarda a chave de negócio que liga cada versão ao mesmo cliente real. Os exemplos usam sintaxe de SQL Server; a lógica é igual noutros warehouses.
CREATE TABLE dim_cliente (
cliente_sk INT IDENTITY(1,1) PRIMARY KEY,
cliente_id INT NOT NULL,
nome VARCHAR(100),
segmento VARCHAR(50),
valid_from DATE NOT NULL,
valid_to DATE NULL,
is_current BIT NOT NULL
);
Passo 3: Fechar as versões antigas que mudaram
A primeira parte da transformação encontra os registos cujo nome ou segmento difere da versão que está no staging e "fecha-os": preenche o valid_to com a data de hoje e coloca is_current = 0. Só as linhas atuais que realmente mudaram são afetadas; as restantes ficam intactas.
UPDATE d
SET d.valid_to = CAST(GETDATE() AS DATE),
d.is_current = 0
FROM dim_cliente AS d
INNER JOIN stg_clientes AS s
ON s.cliente_id = d.cliente_id
WHERE d.is_current = 1
AND (d.segmento <> s.segmento OR d.nome <> s.nome);
Passo 4: Inserir as novas versões
A seguir, inserimos uma linha nova para cada cliente que é novo ou que acabámos de fechar no passo anterior. A nova versão fica marcada como atual (is_current = 1), com valid_from a hoje e valid_to vazio.
INSERT INTO dim_cliente (cliente_id, nome, segmento, valid_from, valid_to, is_current)
SELECT s.cliente_id, s.nome, s.segmento, CAST(GETDATE() AS DATE), NULL, 1
FROM stg_clientes AS s
LEFT JOIN dim_cliente AS d
ON d.cliente_id = s.cliente_id AND d.is_current = 1
WHERE d.cliente_id IS NULL;
O LEFT JOIN seguido de WHERE d.cliente_id IS NULL apanha dois casos ao mesmo tempo: clientes totalmente novos (nunca tiveram linha na dimensão) e clientes cuja versão atual foi fechada no Passo 3 — que, por isso, já não têm nenhuma linha com is_current = 1. Os clientes que não mudaram continuam com a sua linha atual e não são duplicados.
Passo 5: Automatizar a transformação no pipeline ELT
Junta os dois comandos numa única stored procedure ou script, executado sempre depois de carregar a camada de staging. A ordem é importante: primeiro o UPDATE que fecha, depois o INSERT que cria. Um orquestrador como o Azure Data Factory, o Databricks Workflows ou um simples agendador pode correr este passo a cada atualização de dados. Como o processo compara sempre o staging com a versão atual, correr o script duas vezes seguidas não cria duplicados: é idempotente.
Verificar o resultado
A regra de ouro de uma SCD Tipo 2 é simples: cada entidade só pode ter uma versão atual. A consulta seguinte não deve devolver nenhuma linha — se devolver, há um cliente com versões atuais a mais.
SELECT cliente_id, COUNT(*) AS versoes_atuais
FROM dim_cliente
WHERE is_current = 1
GROUP BY cliente_id
HAVING COUNT(*) > 1;
Para ver o histórico, consulta um cliente específico e ordena por valid_from: deverás ver uma linha fechada (com valid_to preenchido e is_current = 0) e uma linha atual. Isso confirma que a mudança foi guardada sem perder o valor anterior.
Conclusão
Com apenas dois comandos SQL — fechar as versões antigas e inserir as novas — já consegues manter um histórico fiável numa dimensão SCD Tipo 2 dentro de um fluxo ELT. A partir daqui, podes adicionar uma coluna de hash para detetar mudanças em muitos atributos de uma só vez, ou usar uma data de fim máxima (por exemplo 9999-12-31) em vez de NULL para simplificar as junções. Que atributos do teu negócio mudam com o tempo e mereciam ficar guardados em histórico?