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

Como criar uma Dimension Slowly Changing Type 4 em Modelação de Dados (Kimball)

João Barros 03 de October de 2026 5 min de leitura

Esta tarefa mostra como criar uma Dimension Slowly Changing Type 4 em Modelação de Dados (Kimball) — uma dimensão que mantém a versão actual e armazena o histórico completo numa tabela separada. É útil quando pretendes consultas rápidas sobre o estado actual e, ao mesmo tempo, conservar todo o historial para auditoria e análises temporais.

Pré-requisitos

  • Conhecimentos básicos de SQL (SELECT, INSERT, UPDATE, JOIN).
  • Um ambiente de base de dados para testes (por exemplo SQL Server, PostgreSQL ou Azure SQL).
  • Dados de exemplo sobre entidades com alterações ao longo do tempo (ex.: clientes com morada e estado).

Passo 1: Entender o que é um SCD Tipo 4

Uma Slowly Changing Dimension (SCD) Tipo 4 separa o historial numa tabela de histórico e mantém apenas a versão actual na dimensão principal. A vantagem: consultas de leitura ao estado actual são rápidas e simples, enquanto o histórico fica disponível para análises detalhadas sem complicar a dimensão principal.

Passo 2: Definir o modelo de tabelas

Vamos criar duas tabelas: Dimension_Current (apenas registos actuais) e Dimension_History (todas as versões históricas). A Dimension_History terá uma chave surrogate, a chave natural da entidade, e campos de validade (valid_from, valid_to). A Dimension_Current tem a mesma chave natural e os atributos actuais.

-- Exemplo em SQL (compatível com SQL Server/Postgres com pequenas adaptações)
CREATE TABLE Dimension_Current (
  customer_id INT PRIMARY KEY,      -- chave natural
  name VARCHAR(200),
  address VARCHAR(300),
  status VARCHAR(50),
  last_updated TIMESTAMP
);

CREATE TABLE Dimension_History (
  history_id SERIAL PRIMARY KEY,    -- chave surrogate
  customer_id INT,                  -- chave natural
  name VARCHAR(200),
  address VARCHAR(300),
  status VARCHAR(50),
  valid_from TIMESTAMP,
  valid_to TIMESTAMP                -- NULL significa ainda válido antes de mover para current
);

Passo 3: Carga inicial dos dados

Popula a Dimension_Current com o estado presente e a Dimension_History com um registo inicial que cobre desde o início até NULL (activo no presente).

-- Supõe que temos uma staging table Stg_Customers com o estado actual
INSERT INTO Dimension_Current (customer_id, name, address, status, last_updated)
SELECT customer_id, name, address, status, now()
FROM Stg_Customers;

INSERT INTO Dimension_History (customer_id, name, address, status, valid_from, valid_to)
SELECT customer_id, name, address, status, now(), NULL
FROM Stg_Customers;

Passo 4: Processo ETL para detectar mudanças e atualizar SCD Tipo 4

O fluxo ETL compara Stg_Customers com Dimension_Current. Para cada registo que mudou, fecha-se o período na Dimension_History (preenche-se valid_to) e insere-se um novo registo histórico com valid_from actual; actualiza-se a Dimension_Current com os novos atributos.

-- Exemplo transaccional simplificado
BEGIN;

-- 1) Fechar versões antigas na history para clientes que mudaram
UPDATE Dimension_History h
SET valid_to = now()
FROM Dimension_Current c
JOIN Stg_Customers s ON s.customer_id = c.customer_id
WHERE h.customer_id = c.customer_id
  AND h.valid_to IS NULL
  AND (c.name <> s.name OR c.address <> s.address OR c.status <> s.status);

-- 2) Inserir nova versão na history
INSERT INTO Dimension_History (customer_id, name, address, status, valid_from, valid_to)
SELECT s.customer_id, s.name, s.address, s.status, now(), NULL
FROM Stg_Customers s
JOIN Dimension_Current c ON s.customer_id = c.customer_id
WHERE (c.name <> s.name OR c.address <> s.address OR c.status <> s.status);

-- 3) Actualizar a dimensão actual
UPDATE Dimension_Current c
SET name = s.name,
    address = s.address,
    status = s.status,
    last_updated = now()
FROM Stg_Customers s
WHERE c.customer_id = s.customer_id
  AND (c.name <> s.name OR c.address <> s.address OR c.status <> s.status);

-- 4) Tratar novos clientes que não existem na Current
INSERT INTO Dimension_Current (customer_id, name, address, status, last_updated)
SELECT s.customer_id, s.name, s.address, s.status, now()
FROM Stg_Customers s
LEFT JOIN Dimension_Current c ON s.customer_id = c.customer_id
WHERE c.customer_id IS NULL;

INSERT INTO Dimension_History (customer_id, name, address, status, valid_from, valid_to)
SELECT s.customer_id, s.name, s.address, s.status, now(), NULL
FROM Stg_Customers s
LEFT JOIN Dimension_History h ON s.customer_id = h.customer_id AND h.valid_to IS NULL
WHERE h.history_id IS NULL;

COMMIT;

Passo 5: Consultas comuns (exemplos)

Exemplos úteis: obter o estado actual (simples) e reconstruir o estado numa data passada (usar Dimension_History).

-- Estado actual (simples)
SELECT * FROM Dimension_Current WHERE customer_id = 123;

-- Estado de um cliente numa data histórica
SELECT *
FROM Dimension_History
WHERE customer_id = 123
  AND valid_from <= '2025-01-15'::timestamp
  AND (valid_to IS NULL OR valid_to > '2025-01-15'::timestamp);

Verificar o resultado

Confirma que Dimension_Current reflecte os valores actuais e que Dimension_History tem entradas com valid_from/valid_to coerentes. Verifica casos de alteração: depois do ETL, o registo antigo na history deve ter valid_to preenchido e existir uma nova linha com valid_to NULL; a Current deve mostrar o novo valor.

Conclusão

A SCD Tipo 4 separa claramente estado actual e histórico, simplificando consultas e mantendo historial completo. Próximos passos: automatizar o processo ETL com jobs (ex.: Azure Data Factory ou SQL Agent), adicionar controlos de qualidade e gerir grandes volumes com partição em Dimension_History. Dica: começa com um subconjunto de clientes para testar e validar o comportamento antes de aplicar em produção.