Rolling 12 meses en DAX: la solución de dos calendarios

· 4 min de lectura
Compartir:

TL;DR

  • Rolling 12 meses dinámico requiere dos calendarios: uno para el slicer, otro para el eje X
  • La relación entre calendarios debe ser inactiva (activarla con USERELATIONSHIP)
  • Patrón complejo: pregunta al cliente si realmente lo necesita antes de implementar
  • A veces un filtro de rango simple es suficiente

El requisito

Parece simple: un gráfico de líneas con los últimos 12 meses, y un segmentador para elegir el mes final.

Seleccionas Diciembre 2024, y el gráfico muestra Enero 2024 - Diciembre 2024. Seleccionas Marzo 2025, muestra Abril 2024 - Marzo 2025.

Fácil, ¿no?

No.

El problema

Si usas un solo calendario, tienes un conflicto de intereses:

  1. El segmentador filtra por mes (Diciembre 2024)
  2. El eje X del gráfico necesita mostrar 12 meses diferentes

Con un solo calendario, cuando filtras por Diciembre, el gráfico solo tiene un punto. El filtro afecta a todo. Es como intentar usar la misma variable para dos cosas distintas: no funciona.

La solución: Dos calendarios

La arquitectura que necesitas es:

  • Calendar: Conectado a la tabla de hechos, alimenta el segmentador
  • Calendar_Display: Alimenta el eje X del gráfico, NO conecta a la tabla de hechos

La clave está en crear una relación INACTIVA entre ambos calendarios. La despiertas solo cuando la necesitas, con USERELATIONSHIP.

El patrón DAX

Ventas Rolling 12 = 
VAR FechaSeleccionada = 
    CALCULATE(
        MAX(Calendar[Date]), 
        ALLEXCEPT(Calendar, Calendar[Year], Calendar[Month])
    )
VAR Ultimos12Meses = 
    DATESINPERIOD(
        Calendar_Display[Date], 
        FechaSeleccionada, 
        -12, 
        MONTH
    )
VAR FechaActualEje = SELECTEDVALUE(Calendar_Display[Date])
VAR EstaEnRango = 
    FechaActualEje >= MINX(Ultimos12Meses, [Date]) &&
    FechaActualEje <= MAXX(Ultimos12Meses, [Date])
RETURN
IF(
    EstaEnRango,
    CALCULATE(
        [Ventas],
        REMOVEFILTERS(Calendar),
        KEEPFILTERS(Ultimos12Meses),
        USERELATIONSHIP(Calendar[Date], Calendar_Display[Date])
    ),
    BLANK()
)

Qué hace cada parte

  1. FechaSeleccionada: Captura lo que el usuario eligió en el segmentador
  2. Ultimos12Meses: Calcula el rango de 12 meses hacia atrás desde esa fecha
  3. REMOVEFILTERS: Limpia el filtro del segmentador (si no, solo tendrías 1 mes en el gráfico)
  4. KEEPFILTERS: Mantiene el rango de 12 meses que acabamos de calcular
  5. USERELATIONSHIP: Activa la relación inactiva entre calendarios
  6. EstaEnRango: Evita mostrar datos fuera del rango (si no, te salen puntos fantasma)

Por qué la relación tiene que ser inactiva

Si la activas permanentemente, creas ambigüedad en el modelo. Power BI ve dos caminos posibles entre el calendario y los hechos, y no sabe cuál seguir.

Por eso la dejas inactiva por defecto y la activas solo en las medidas específicas que la necesitan. Es como un interruptor: encendido solo cuando hace falta.

Antes de implementarlo

Este patrón es complejo y difícil de mantener. Antes de meterte en este jardín, pregunta al cliente si realmente necesita un rolling dinámico o si le vale con un filtro simple de rango de fechas.

A veces la respuesta es “ah, pues sí, con un filtro de fecha me vale”. Y te acabas de ahorrar tres horas de debug.


¿Te ha servido? Tengo más patrones DAX oscuros en el cajón.

¿Empezando con DAX? Lee primero Qué es DAX en Power BI: Guía para principiantes.

¿Problemas con relaciones inactivas? Lee Power BI desactivó tu relación y no te avisó para entender USERELATIONSHIP a fondo.

¿Te ha sido útil? Compártelo

Compartir:

También te puede interesar