Saltar al contenido

lección 5

Slowly Changing Dimensions: cuando el mundo cambia

Aprende a manejar cambios en las dimensiones: qué pasa cuando un cliente cambia de país o un producto cambia de categoría.

55 min

Hasta ahora hemos tratado las dimensiones como si fueran estáticas: un cliente SIEMPRE vive en Madrid, un producto SIEMPRE pertenece a la categoría "Electrónica". Pero la realidad es más cruel. Los clientes se mudan. Los productos se recategorizan. Las tiendas cambian de gerente. Los empleados cambian de departamento. ¿Qué hacemos cuando el mundo cambia y nuestro warehouse tiene que reflejarlo?

Este problema se llama Slowly Changing Dimensions (SCD) — dimensiones que cambian lentamente. "Lentamente" porque no cambian cada segundo (eso sería un hecho), sino ocasionalmente: un cliente cambia de dirección una vez al año, un producto se recategoriza una vez cada pocos meses. Kimball definió 7 tipos de SCD, pero en la práctica usarás 3: tipo 1 (sobrescribir), tipo 2 (historificar) y tipo 3 (columnas anterior/actual).

### SCD Tipo 0: no hacer nada (atributos fijos)

Algunos atributos NUNCA deberían cambiar: la fecha de nacimiento de un cliente, el código EAN de un producto, la fecha de apertura de una tienda. Estos son atributos "fijos" — si alguien intenta cambiarlos, probablemente es un error de datos. Para estos, simplemente no permites actualizaciones. Es el caso más simple y suele aplicarse a identifiers naturales.

### SCD Tipo 1: sobrescribir el valor anterior

El tipo más simple: cuando el atributo cambia, sobrescribes el valor anterior con el nuevo. El histórico se PIERDE. Si un cliente se muda de Madrid a Barcelona, actualizas city="Barcelona" y ya no sabes que antes vivía en Madrid.

1-- SCD Tipo 1: Sobrescribir (se pierde el histórico)
2
3-- Antes del cambio:
4-- | customer_key | name | city | segment |
5-- | 42 | Ana López | Madrid | VIP |
6
7-- Ana se muda a Barcelona → UPDATE directo
8UPDATE dim_customer
9SET city = 'Barcelona'
10WHERE customer_key = 42;
11
12-- Después del cambio:
13-- | customer_key | name | city | segment |
14-- | 42 | Ana López | Barcelona | VIP |
15
16-- Problema: TODAS las ventas históricas de Ana ahora "pertenecen"
17-- a Barcelona, incluso las que hizo cuando vivía en Madrid.
18-- Si alguien consulta "ventas en Madrid 2023" ya no incluirá a Ana.

SCD Tipo 1 es simple pero destructivo: pierdes la historia. Úsalo solo cuando el histórico no importa.

¿Cuándo usar Tipo 1? Cuando el histórico NO importa para el análisis. Ejemplos: corrección de typos (customer_name tenía un error), actualización de email, campos que eran incorrectos desde el principio. También se usa para atributos donde el negocio siempre quiere ver el valor ACTUAL (segmento de cliente actualizado por un modelo de ML cada mes).

### SCD Tipo 2: preservar toda la historia

El tipo más poderoso y más usado en warehouses serios: cuando un atributo cambia, NO sobrescribes. En su lugar, "cierras" la fila actual (marcándola como no vigente) y creas una NUEVA fila con el valor actualizado. El cliente ahora tiene DOS filas en dim_customer: una para cuando vivía en Madrid y otra para Barcelona. Cada una con su propio surrogate key.

1-- SCD Tipo 2: Historificar (preserva TODA la historia)
2
3-- Antes: Ana vive en Madrid
4-- | customer_key | customer_id | name | city | is_current | valid_from | valid_to |
5-- | 42 | C-001 | Ana López | Madrid | TRUE | 2020-03-15 | 9999-12-31 |
6
7-- Ana se muda a Barcelona el 2024-06-01:
8-- Paso 1: "Cerrar" la fila actual
9UPDATE dim_customer
10SET is_current = FALSE,
11 valid_to = '2024-05-31'
12WHERE customer_key = 42;
13
14-- Paso 2: Insertar nueva fila con nuevo surrogate key
15INSERT INTO dim_customer (customer_id, name, city, is_current, valid_from, valid_to)
16VALUES ('C-001', 'Ana López', 'Barcelona', TRUE, '2024-06-01', '9999-12-31');
17-- Se genera customer_key = 1847 (nuevo surrogate key)
18
19-- Resultado:
20-- | customer_key | customer_id | name | city | is_current | valid_from | valid_to |
21-- | 42 | C-001 | Ana López | Madrid | FALSE | 2020-03-15 | 2024-05-31 |
22-- | 1847 | C-001 | Ana López | Barcelona | TRUE | 2024-06-01 | 9999-12-31 |
23
24-- Ahora las ventas de Ana en 2023 apuntan a customer_key=42 (Madrid)
25-- y las ventas de 2024 en adelante apuntan a customer_key=1847 (Barcelona)
26-- ¡La historia está preservada!

SCD Tipo 2 crea versiones. El surrogate key es la clave para que el histórico funcione.

La magia del Tipo 2 está en las surrogate keys. Las ventas antiguas de Ana apuntan a customer_key=42 (versión Madrid). Las ventas nuevas apuntarán a customer_key=1847 (versión Barcelona). El histórico se preserva AUTOMÁTICAMENTE sin tocar la fact table. Cuando alguien consulta "ventas en Madrid 2023", Ana aparece porque customer_key=42 tiene city=Madrid.

### SCD Tipo 3: columnas anterior/actual

Un compromiso intermedio: guardas el valor ANTERIOR en una columna extra. No necesitas filas nuevas, pero solo puedes ver UN cambio hacia atrás. Es útil cuando el negocio quiere comparar "antes vs ahora" pero no necesita todo el historial completo.

1-- SCD Tipo 3: Columnas anterior/actual
2
3-- | customer_key | name | current_city | previous_city | city_changed_on |
4-- | 42 | Ana López | Barcelona | Madrid | 2024-06-01 |
5
6-- Ventaja: simple, una sola fila por cliente
7-- Desventaja: solo 1 cambio en la historia. Si Ana se muda otra vez
8-- (Barcelona → Valencia), pierdes que estuvo en Madrid.

Tipo 3 es un compromiso: ves un antes/después, pero no el historial completo.

El error que más cuesta dinero: aplicar SCD Tipo 1 a atributos que SÍ importan históricamente. He visto una cadena de retail que sobrescribía la región de sus tiendas. Cuando reorganizaron las regiones, TODOS los históricos de ventas se reasignaron. Los reportes de performance regional se volvieron inútiles — "la región Norte creció 40%" era mentira, simplemente le habían asignado tiendas nuevas. La solución fue un SCD Tipo 2 y una migración dolorosa de 6 semanas.

### Cuándo usar cada tipo: guía práctica

  • Tipo 0: atributos que NUNCA cambian (fecha de nacimiento, código EAN)
  • Tipo 1: correcciones de errores, atributos donde solo importa el valor actual (email, teléfono)
  • Tipo 2: atributos críticos para el análisis histórico (segmento, región, categoría, precio)
  • Tipo 3: atributos donde necesitas comparar antes/ahora pero no todo el historial (plan de suscripción)
  • Combinación: es COMÚN usar tipos diferentes para distintos atributos de la MISMA dimensión

Mi regla personal: si el CFO puede preguntarte "¿cómo eran las ventas por X cuando Y tenía el valor anterior?", necesitas Tipo 2 para ese atributo. Si la pregunta es "¿cuál es el valor actual de X?", Tipo 1 es suficiente. En la duda, Tipo 2 — guardar historia es barato, reconstruirla después es carísimo.

### Implementación de SCD Tipo 2 en SQL

1-- Patrón completo de SCD Tipo 2 con MERGE (PostgreSQL 15+)
2
3-- Paso 1: Detectar cambios (comparar fuente vs dimensión actual)
4WITH source_data AS (
5 SELECT customer_id, name, city, segment
6 FROM staging_customers -- datos frescos del sistema fuente
7),
8changes AS (
9 SELECT s.*
10 FROM source_data s
11 JOIN dim_customer d ON s.customer_id = d.customer_id AND d.is_current = TRUE
12 WHERE s.city != d.city OR s.segment != d.segment -- detectar cambios
13)
14-- Paso 2: Cerrar registros que cambiaron
15UPDATE dim_customer d
16SET is_current = FALSE,
17 valid_to = CURRENT_DATE - INTERVAL '1 day'
18FROM changes c
19WHERE d.customer_id = c.customer_id AND d.is_current = TRUE;
20
21-- Paso 3: Insertar nuevas versiones
22INSERT INTO dim_customer (customer_id, name, city, segment, is_current, valid_from, valid_to)
23SELECT customer_id, name, city, segment, TRUE, CURRENT_DATE, '9999-12-31'::DATE
24FROM changes;
25
26-- Paso 4: Insertar clientes completamente nuevos (no existían antes)
27INSERT INTO dim_customer (customer_id, name, city, segment, is_current, valid_from, valid_to)
28SELECT s.customer_id, s.name, s.city, s.segment, TRUE, CURRENT_DATE, '9999-12-31'::DATE
29FROM source_data s
30LEFT JOIN dim_customer d ON s.customer_id = d.customer_id
31WHERE d.customer_key IS NULL;

Patrón ETL para SCD Tipo 2: detectar cambios → cerrar vigentes → insertar nuevas versiones.

## ejercicios

[01]

Elegir el tipo de SCD correcto

Para cada atributo de dim_customer, decide qué tipo de SCD aplicar y justifica tu elección.

Cargando editor...
[02]

Implementar el cierre de un SCD Tipo 2

El producto "Smart TV Samsung 55" (product_id=P-100) cambió de categoría de "Electrónica" a "Hogar Inteligente" el 15 de marzo 2024. Escribe las sentencias SQL para implementar el SCD Tipo 2. Ejercicio autocontenido: el estado inicial ya está sembrado. Ejecútalo en DuckDB.

💡 Resultado esperado

product_key | category          | is_current | valid_from | valid_to
77          | Electrónica       | false      | 2022-01-01 | 2024-03-14
1523        | Hogar Inteligente | true       | 2024-03-15 | 9999-12-31
Cargando editor...
[03]

Consultar datos con SCD Tipo 2

Dado un modelo con SCD Tipo 2 en dim_customer, escribe una query que muestre las ventas de Ana (customer_id=C-001) separadas por la ciudad donde vivía EN EL MOMENTO de cada venta. Ejercicio autocontenido: el modelo con las 2 versiones de Ana ya está sembrado. Ejecútalo en DuckDB.

💡 Resultado esperado

ciudad_al_momento_de_compra | num_compras | total_gastado
Madrid                      | 2           | 350.50
Barcelona                   | 1           | 89.30
Cargando editor...
[04]

Diseñar dimensión con SCD mixto

Diseña la tabla dim_employee para un call center donde necesitas: Tipo 0 para hire_date, Tipo 1 para phone, Tipo 2 para department y team_lead, Tipo 3 para job_title. Incluye todas las columnas necesarias.

Cargando editor...

Regístrate para guardar tu progreso.

## comentarios

Reporta erratas, ayuda a otros o comparte tu opinión. Sé constructivo.

Inicia sesión para comentar y responder.

cargando comentarios...