DAX Avanzado: CALCULATE, FILTER y Contexto
CALCULATE es la función más poderosa de DAX. Dominarla es la diferencia entre un usuario básico y un experto en Power BI.
CALCULATE en profundidad
CALCULATE hace dos cosas:
- Evalúa una expresión.
- Modifica el contexto de filtro antes de evaluarla.
CALCULATE(<expresión>, <filtro1>, <filtro2>, ...)
Ejemplo fundamental
// Sin CALCULATE: respeta todos los filtros del reporte
Total Ventas = SUM(Ventas[Monto])
// Con CALCULATE: modifica el contexto de filtro
Ventas México =
CALCULATE(
SUM(Ventas[Monto]),
Clientes[País] = "México"
)
// Siempre muestra ventas de México, sin importar qué filtre el usuario
Modificadores de filtro
ALL — Remueve filtros
// Remueve TODOS los filtros de una tabla
Total General =
CALCULATE([Ingresos], ALL(Ventas))
// Remueve filtro de una columna específica
Total Sin Categoría =
CALCULATE([Ingresos], ALL(Productos[Categoría]))
// Participación porcentual
% del Total =
DIVIDE(
[Ingresos],
CALCULATE([Ingresos], ALL(Productos[Categoría])),
0
)
ALLEXCEPT — Remueve todos los filtros excepto los especificados
// Mantiene solo el filtro de País, remueve todo lo demás
% en País =
DIVIDE(
[Ingresos],
CALCULATE([Ingresos], ALLEXCEPT(Ventas, Clientes[País])),
0
)
REMOVEFILTERS — Alias moderno de ALL en contexto de filtro
Total Sin Filtros =
CALCULATE([Ingresos], REMOVEFILTERS())
KEEPFILTERS — Intersecta en vez de reemplazar
// Sin KEEPFILTERS: reemplaza el filtro de categoría
Ventas Electrónica =
CALCULATE([Ingresos], Productos[Categoría] = "Electrónica")
// Si el usuario filtra "Ropa", IGNORA ese filtro y muestra Electrónica
// Con KEEPFILTERS: intersecta con el filtro del usuario
Ventas Electrónica Safe =
CALCULATE([Ingresos], KEEPFILTERS(Productos[Categoría] = "Electrónica"))
// Si el usuario filtra "Ropa", intersecta Ropa ∩ Electrónica = vacío = 0
FILTER — Tabla de filtro explicita
// FILTER retorna una tabla filtrada
Ventas VIP =
CALCULATE(
[Ingresos],
FILTER(Clientes, Clientes[Total Compras] > 100000)
)
// FILTER puede usar medidas (los filtros simples no pueden)
Ventas de Top Clientes =
CALCULATE(
[Ingresos],
FILTER(
ALL(Clientes[Nombre]),
[Ingresos] > 50000
)
)
Cuándo usar FILTER vs filtro directo
| Escenario | Usar |
|---|---|
| Filtrar por valor literal | Filtro directo: Tabla[Col] = "valor" |
| Filtrar por medida | FILTER() |
| Filtrar con operadores complejos | FILTER() |
| Performance importa | Filtro directo (más rápido) |
Transición de contexto (Context Transition)
Cuando CALCULATE se usa dentro de un contexto de fila (columna calculada o iterador), convierte automáticamente el contexto de fila en contexto de filtro.
// En una columna calculada de la tabla Clientes:
Total Compras Cliente = CALCULATE(SUM(Ventas[Monto]))
// CALCULATE detecta el contexto de fila (cada cliente)
// y lo convierte en filtro: filtra Ventas por ese cliente
SELECTEDVALUE y HASONEVALUE
// Obtener el valor seleccionado actualmente
País Seleccionado = SELECTEDVALUE(Clientes[País], "Todos")
// Lógica condicional basada en selección
KPI Dinámico =
SWITCH(
SELECTEDVALUE(SlicerMétrica[Métrica]),
"Ingresos", [Ingresos],
"Margen", [Margen %],
"Clientes", [Num Clientes],
[Ingresos]
)
VALUES y DISTINCT
// Contar valores únicos con detalle
Num Países = COUNTROWS(VALUES(Clientes[País]))
// Iterar sobre valores únicos
Promedio por País =
AVERAGEX(
VALUES(Clientes[País]),
[Ingresos]
)
Ranking dinámico
Ranking =
RANKX(
ALL(Productos[Nombre]),
[Ingresos],
,
DESC,
Dense
)
Top N dinámico con slicer
// Medida que muestra el valor solo si está en el Top N
Ingresos Top N =
VAR TopN = SELECTEDVALUE(SlicerTopN[N], 10)
VAR MiRanking = [Ranking]
RETURN
IF(MiRanking <= TopN, [Ingresos], BLANK())
Patrones avanzados
ABC Analysis
Clasificación ABC =
VAR TotalGeneral = CALCULATE([Ingresos], ALL(Productos))
VAR IngresoProducto = [Ingresos]
VAR Acumulado =
CALCULATE(
[Ingresos],
FILTER(
ALL(Productos[Nombre]),
[Ingresos] >= IngresoProducto
)
)
VAR PctAcumulado = DIVIDE(Acumulado, TotalGeneral)
RETURN
SWITCH(TRUE(),
PctAcumulado <= 0.80, "A",
PctAcumulado <= 0.95, "B",
"C"
)
Nuevos clientes vs recurrentes
Clientes Nuevos =
COUNTROWS(
FILTER(
VALUES(Clientes[ClienteID]),
CALCULATE(MIN(Ventas[Fecha])) >= MIN(Calendario[Date]) &&
CALCULATE(MIN(Ventas[Fecha])) <= MAX(Calendario[Date])
)
)
Resumen
CALCULATE modifica el contexto de filtro y es la función central de DAX. ALL remueve filtros, FILTER crea filtros complejos, KEEPFILTERS intersecta. La transición de contexto convierte contexto de fila en filtro automáticamente. Estos patrones son la base de métricas avanzadas como ranking, ABC y análisis de cohortes.