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

Cómo crear una Dimension Slowly Changing Type 4 en Modelado de Datos (Kimball)

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

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.