Cómo crear una Dimension Slowly Changing Type 4 en Modelado de Datos (Kimball)
Esta tarea muestra cómo crear una Dimension Slowly Changing Type 4 en Modelado de Datos (Kimball) — una dimensión que mantiene la versión actual y almacena el historial completo en una tabla separada. Es útil cuando quieres consultas rápidas sobre el estado actual y, al mismo tiempo, conservar todo el historial para auditoría y análisis temporales.
Prerequisitos
- Conocimientos básicos de SQL (SELECT, INSERT, UPDATE, JOIN).
- Un entorno de base de datos para pruebas (por ejemplo SQL Server, PostgreSQL o Azure SQL).
- Datos de ejemplo sobre entidades con cambios a lo largo del tiempo (p. ej.: clientes con dirección y estado).
Paso 1: Entender qué es un SCD Tipo 4
Una Slowly Changing Dimension (SCD) Tipo 4 separa el historial en una tabla de historial y mantiene solo la versión actual en la dimensión principal. La ventaja: las consultas de lectura sobre el estado actual son rápidas y sencillas, mientras que el historial queda disponible para análisis detallados sin complicar la dimensión principal.
Paso 2: Definir el modelo de tablas
Vamos a crear dos tablas: Dimension_Current (solo registros actuales) y Dimension_History (todas las versiones históricas). Dimension_History tendrá una clave surrogate, la clave natural de la entidad, y campos de validez (valid_from, valid_to). Dimension_Current tiene la misma clave natural y los atributos actuales.
-- 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
);
Paso 3: Carga inicial de los datos
Puebla Dimension_Current con el estado presente y Dimension_History con un registro inicial que cubre desde el inicio hasta NULL (activo en el 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;
Paso 4: Proceso ETL para detectar cambios y actualizar SCD Tipo 4
El flujo ETL compara Stg_Customers con Dimension_Current. Para cada registro que haya cambiado, se cierra el periodo en Dimension_History (se rellena valid_to) y se inserta un nuevo registro histórico con valid_from actual; se actualiza Dimension_Current con los nuevos 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;
Paso 5: Consultas comunes (ejemplos)
Ejemplos útiles: obtener el estado actual (sencillo) y reconstruir el estado en una fecha pasada (usar Dimension_History).
-- Estado actual (simples)
SELECT * FROM Dimension_Current WHERE customer_id = 123;
-- Estado de un cliente en una fecha 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 el resultado
Confirma que Dimension_Current refleja los valores actuales y que Dimension_History tiene entradas con valid_from/valid_to coherentes. Verifica casos de cambio: después del ETL, el registro antiguo en history debe tener valid_to rellenado y existir una nueva fila con valid_to NULL; la Current debe mostrar el nuevo valor.
Conclusión
El SCD Tipo 4 separa claramente estado actual e histórico, simplificando consultas y manteniendo historial completo. Próximos pasos: automatizar el proceso ETL con jobs (p. ej.: Azure Data Factory o SQL Agent), añadir controles de calidad y gestionar grandes volúmenes con particionado en Dimension_History. Consejo: empieza con un subconjunto de clientes para probar y validar el comportamiento antes de aplicar en producción.