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

Cómo crear una Fact table de tipo 'Snapshot por Evento' en Modelado de Datos (Kimball)

João Barros 17 de September de 2026 5 min de lectura

Este tutorial muestra cómo crear una Fact table de tipo 'Snapshot por Evento' en Modelado de Datos (Kimball): una tabla de hechos que registra el estado de una entidad cada vez que ocurre un evento relevante. Es útil para analizar la evolución por evento (p. ej.: cambios de estado de pedidos) sin confligir con snapshots periódicos ni con accumulating snapshots.

Prerequisitos

  • Conocimientos básicos de Modelado Dimensional (Fact/DIMensions).
  • Acceso a una base de datos SQL (p. ej.: SQL Server, PostgreSQL).
  • Datos de origen con eventos (p. ej.: logs de estado de pedido con timestamp).

Paso 1: Entender cuándo usar un Snapshot por Evento

Un Snapshot por Evento graba el estado de la entidad cada vez que ocurre un evento que interesa para el análisis (p. ej.: cambio de estado, registro de pago). Úselo cuando necesite el historial por evento, sin perder el contexto temporal. Evita la pérdida de granularidad que ocurriría con snapshots periódicos y permite análisis de funnel y lead time entre eventos.

Paso 2: Definir la granularidad y las claves

Decida la granularidad: generalmente una fila por (entity_id, event_id/timestamp). Defina claves:

  • Surrogate key de la fact (fact_snapshot_id) — identidad de la tabla de hechos.
  • Natural keys: entity_id y event_timestamp (o event_id si existe).
  • Foreign keys hacia dimensiones conformadas (p. ej.: dim_date, dim_user, dim_location).
-- Exemplo de definição mínima em SQL (SQL Server/Postgres sintaxe geral)
CREATE TABLE fact_event_snapshot (
  fact_snapshot_id BIGSERIAL PRIMARY KEY,
  entity_id VARCHAR(50) NOT NULL,
  event_timestamp TIMESTAMP NOT NULL,
  event_type VARCHAR(50) NOT NULL,
  status_before VARCHAR(50),
  status_after VARCHAR(50),
  amount NUMERIC(18,2),
  dim_date_key INT, -- FK para dim_date
  dim_user_key INT, -- FK para dim_user
  load_batch_id VARCHAR(50) -- rastreio de carga
);

Paso 3: Mapear atributos e identificar dimensiones

Elija qué atributos van a la fact (medidas y atributos degenerate) y cuáles van a dimensiones. Medidas: valores que se agregan (amount, quantity). Atributos de contexto que se repiten y tienen baja cardinalidad deben ir a dimensiones (status, event_type puede ser una dimensión pequeña o string directo en la fact si es útil para rendimiento).

Paso 4: Extracción y transformación (ETL) — lógica de captura por evento

Implemente la lógica que detecta nuevos eventos y crea un snapshot por evento. Normalmente: leer source_events, para cada evento construir un registro con estado antes/después y enlazar claves de dimensión.

-- Exemplo ETL simplificado em SQL: inserir novos snapshots
INSERT INTO fact_event_snapshot (
  entity_id, event_timestamp, event_type, status_before, status_after, amount, dim_date_key, dim_user_key, load_batch_id
)
SELECT
  e.entity_id,
  e.event_ts,
  e.event_type,
  e.status_before,
  e.status_after,
  e.amount,
  d.date_key,
  u.user_key,
  :batch_id
FROM staging_events e
LEFT JOIN dim_date d ON d.calendar_date = DATE(e.event_ts)
LEFT JOIN dim_user u ON u.user_id = e.user_id
WHERE e.processed_flag = 0; -- só novos eventos

Paso 5: Manejar duplicados e idempotencia

Evitar insertar duplicados es crítico. Use una restricción única o deduplicación antes de insertar. Una opción es usar una clave única lógica (entity_id + event_timestamp + event_type).

-- Criar índice único para evitar duplicados
ALTER TABLE fact_event_snapshot
ADD CONSTRAINT uq_event_snapshot UNIQUE (entity_id, event_timestamp, event_type);

-- Inserção defensiva (exemplo Postgres)
INSERT INTO fact_event_snapshot (...)
SELECT ...
ON CONFLICT (entity_id, event_timestamp, event_type) DO NOTHING;

Paso 6: Actualizaciones de atributos y Slowly Changing Dimensions

Si los atributos relacionados con las dimensiones cambian, trátelos como Slowly Changing Dimensions (SCD). La fact_snapshot debe referenciar la versión correcta de la dimensión (surrogate key) para preservar el historial. En el ETL, haga lookup de la dimensión actual o histórica según sea necesario.

Verificar el resultado

Verifique que cada evento relevante tenga una fila en la fact:

  • Contar eventos en la fuente vs filas en la fact por período: SELECT COUNT(*) por intervalo.
  • Verificar unicidad: SELECT entity_id, event_timestamp, COUNT(*) HAVING COUNT(*) > 1.
  • Probar queries analíticas: tiempo medio entre event_type = 'A' y event_type = 'B' por entity_id.
-- Exemplos de verificação
-- 1) Verificar total
SELECT COUNT(*) FROM staging_events WHERE processed_flag = 0;
SELECT COUNT(*) FROM fact_event_snapshot WHERE load_batch_id = :batch_id;

-- 2) Duplicados
SELECT entity_id, event_timestamp, event_type, COUNT(*)
FROM fact_event_snapshot
GROUP BY entity_id, event_timestamp, event_type
HAVING COUNT(*) > 1;

-- 3) Exemplo analítico: tempo entre eventos
SELECT f1.entity_id, EXTRACT(EPOCH FROM (f2.event_timestamp - f1.event_timestamp))/3600 AS hours_between
FROM fact_event_snapshot f1
JOIN fact_event_snapshot f2 ON f1.entity_id = f2.entity_id
WHERE f1.event_type = 'A' AND f2.event_type = 'B' AND f2.event_timestamp > f1.event_timestamp;

Conclusión

Una Fact table 'Snapshot por Evento' ofrece granularidad para analizar la evolución por acontecimientos sin perder historial. Próximos pasos: integrar con Power BI para visualizaciones de funnel y tiempos, automatizar la rutina ETL y añadir métricas de calidad. Consejo: empiece con índices/constraints para idempotencia y validación simple para evitar datos duplicados — ¿cuál es el primer evento crítico que va a capturar en su caso?