Funciones de Relaciones
RELATED, RELATEDTABLE, USERELATIONSHIP, CROSSFILTER — controla cómo fluye el contexto entre tablas
Intermedio
Avanzado
Cómo funcionan las relaciones en DAX 🤔
En Power BI, las relaciones conectan las tablas de tu modelo de datos. Entender cómo navegar por estas relaciones es fundamental para escribir DAX avanzado.
Modelo estrella típico
'Clientes' 'Productos' 'Calendario'
│ │ │
│ (uno) │ (uno) │ (uno)
│ │ │
└────────────────────┼────────────────────┘
│
'Ventas' (muchos)
[IDCliente, IDProducto, Fecha, Importe]
Características de las relaciones en Power BI
- Dirección de filtro: De la tabla "uno" hacia la tabla "muchos" (por defecto). Los filtros aplicados a Clientes, Productos o Calendario fluyen automáticamente a Ventas.
- Cardinalidad:
- Uno a muchos (1:N) — la más común
- Muchos a muchos (N:M) — requiere configuración especial
- Uno a uno (1:1) — poco común
- Estado:
- Activa — solo puede haber UNA relación activa entre dos tablas
- Inactiva — relaciones adicionales que deben activarse con USERELATIONSHIP
Las 4 funciones de relaciones en DAX
- RELATED — navega "río arriba" (de la tabla muchos a la tabla uno)
- RELATEDTABLE — navega "río abajo" (de la tabla uno a la tabla muchos)
- USERELATIONSHIP — activa una relación inactiva temporalmente
- CROSSFILTER — cambia la dirección de filtrado o desactiva el filtrado cruzado
Analogía kawaii 🌸
Piensa en las relaciones como canales de agua:
Piensa en las relaciones como canales de agua:
- El agua (los filtros) fluye desde la montaña (tabla "uno") hacia el río (tabla "muchos")
- RELATED es como nadar río arriba — vas desde Ventas hacia Productos/Clientes
- RELATEDTABLE es como dejarse llevar río abajo — vas desde Productos/Clientes hacia Ventas
- USERELATIONSHIP abre una compuerta secundaria
- CROSSFILTER cambia la dirección del canal
🔄
USERELATIONSHIP — activar relaciones inactivas
USERELATIONSHIP(<columna1>, <columna2>)
Avanzado
Modificador de CALCULATE que activa una relación INACTIVA para la duración del cálculo. Power BI solo permite una relación activa entre dos tablas — si necesitas filtrar por una segunda relación, debes marcarla como inactiva en el modelo y activarla temporalmente con USERELATIONSHIP.
Caso de uso típico — múltiples relaciones fecha
Escenario muy común: tabla Ventas con dos columnas de fecha:
- FechaPedido — fecha en que se realizó el pedido
- FechaEntrega — fecha en que se entregó
Solo UNA puede ser la relación activa con el Calendario. La otra debe ser inactiva y se activa con USERELATIONSHIP cuando la necesitas.
// En el modelo:
// Activa: Ventas[FechaPedido] → Calendario[Date]
// Inactiva: Ventas[FechaEntrega] → Calendario[Date] (marcada como inactiva)
// Medida usando la relación activa (FechaPedido):
Pedidos por Fecha = COUNTROWS('Ventas')
// Esto filtra por FechaPedido automáticamente
// Medida usando la relación INACTIVA (FechaEntrega):
Entregas por Fecha =
CALCULATE(
COUNTROWS('Ventas'),
USERELATIONSHIP('Ventas'[FechaEntrega], 'Calendario'[Date])
)
// USERELATIONSHIP activa temporalmente la relación de FechaEntrega
// para este cálculo específico
// Ambas en el mismo informe con el mismo slicer de fecha:
// El slicer filtra la fecha, USERELATIONSHIP determina cuál columna se usa
Ejemplo 2 — tabla de roles en RRHH
// Tabla Empleados con:
// ManagerID → relación inactiva con Empleados[EmpleadoID]
// para la jerarquía de reporting
Nombre Manager =
CALCULATE(
MAX('Empleados'[Nombre]),
USERELATIONSHIP('Empleados'[ManagerID], 'Empleados'[EmpleadoID])
)
⚠️ Limitaciones de USERELATIONSHIP
USERELATIONSHIP solo puede activar relaciones que ya existen en el modelo (aunque sean inactivas). No puede crear relaciones nuevas en tiempo de ejecución — para eso existe TREATAS.
Además, USERELATIONSHIP suspende la relación activa entre esas dos tablas mientras dura el cálculo.
USERELATIONSHIP solo puede activar relaciones que ya existen en el modelo (aunque sean inactivas). No puede crear relaciones nuevas en tiempo de ejecución — para eso existe TREATAS.
Además, USERELATIONSHIP suspende la relación activa entre esas dos tablas mientras dura el cálculo.
↔️
CROSSFILTER — cambiar la dirección de filtrado
CROSSFILTER(<columna1>, <columna2>, <dirección>)
Avanzado
Modificador de CALCULATE que cambia la dirección de filtrado cruzado de una relación para la duración del cálculo. Los valores posibles de dirección son:
- NONE — desactiva el filtrado por esta relación
- ONEWAY — filtra solo en la dirección "uno → muchos" (comportamiento normal)
- BOTH — filtra en ambas direcciones (bidireccional)
Por qué es importante
Por defecto, los filtros fluyen de la tabla "uno" a la tabla "muchos". A veces necesitas que el filtro fluya en la dirección contraria.
En lugar de cambiar el modelo permanentemente (lo cual puede crear ambigüedad), usa CROSSFILTER para activar la bidireccionalidad solo cuando la necesitas.
Ejemplo — contar clientes que compraron un producto específico
// Sin CROSSFILTER, el filtro de Productos no llega a Clientes
// (el filtro va Productos → Ventas, pero no Ventas → Clientes de vuelta)
// ❌ Puede no funcionar según el modelo:
Clientes que compraron Laptop =
CALCULATE(
DISTINCTCOUNT('Ventas'[IDCliente]),
'Productos'[Nombre] = "Laptop Pro"
)
// ✅ Con CROSSFILTER (el filtro fluye Productos → Ventas → Clientes):
Clientes que compraron Laptop v2 =
CALCULATE(
DISTINCTCOUNT('Clientes'[ID]),
CROSSFILTER('Ventas'[IDProducto], 'Productos'[ID], BOTH),
'Productos'[Nombre] = "Laptop Pro"
)
Ejemplo — desactivar una relación temporalmente
// Calcular el total sin que una relación filtre:
Total Sin Filtro Region =
CALCULATE(
[Total Ventas],
CROSSFILTER('Ventas'[IDRegion], 'Regiones'[ID], NONE)
)
🏆 Best practice: bidireccionalidad selectiva
La bidireccionalidad permanente en el modelo puede crear ambigüedad y reducir el rendimiento (especialmente en modelos complejos).
El patrón recomendado por SQLBI: mantener las relaciones unidireccionales en el modelo y usar CROSSFILTER(BOTH) solo cuando sea estrictamente necesario en una medida concreta.
La bidireccionalidad permanente en el modelo puede crear ambigüedad y reducir el rendimiento (especialmente en modelos complejos).
El patrón recomendado por SQLBI: mantener las relaciones unidireccionales en el modelo y usar CROSSFILTER(BOTH) solo cuando sea estrictamente necesario en una medida concreta.
🏆
Patrones avanzados con relaciones
Patrón 1 — Ventas del mes de entrega (relación inactiva)
Ventas por Entrega =
CALCULATE(
SUM('Ventas'[Importe]),
USERELATIONSHIP('Ventas'[FechaEntrega], 'Calendario'[Date])
)
Patrón 2 — Contar clientes únicos que compraron una categoría
Clientes por Categoría =
CALCULATE(
DISTINCTCOUNT('Clientes'[ID]),
CROSSFILTER('Ventas'[IDCliente], 'Clientes'[ID], BOTH)
)
Patrón 3 — Segmentación de clientes en columna calculada
// Añadir el segmento de cliente a cada venta (para análisis rápido):
'Ventas'[Segmento] = RELATED('Clientes'[Segmento])
'Ventas'[País] = RELATED('Clientes'[País])
'Ventas'[Categoría Producto] = RELATED('Productos'[Categoría])
Patrón 4 — Tabla de hechos enriquecida para análisis
Ventas Enriquecidas =
ADDCOLUMNS(
'Ventas',
"País Cliente", RELATED('Clientes'[País]),
"Segmento", RELATED('Clientes'[Segmento]),
"Categoría", RELATED('Productos'[Categoría]),
"Año", RELATED('Calendario'[Año]),
"Trimestre", RELATED('Calendario'[Trimestre])
)
🚀 Siguiente paso
Controlas el flujo de datos entre tablas — eso es manejar DAX a nivel avanzado. A continuación, las funciones de Información — el grupo IS... que te ayuda a entender en qué contexto está evaluándose tu medida.
Controlas el flujo de datos entre tablas — eso es manejar DAX a nivel avanzado. A continuación, las funciones de Información — el grupo IS... que te ayuda a entender en qué contexto está evaluándose tu medida.