Funciones Padre-Hijo
PATH, PATHITEM, PATHLENGTH, PATHCONTAINS — maneja jerarquías irregulares como organigramas y planes de cuentas
¿Qué es una jerarquía padre-hijo? El problema que resuelven
Imagina que tienes un organigrama de empresa guardado en una tabla. Cada persona tiene un ID y el ID de su manager directo. La jerarquía tiene profundidad variable — la directora tiene 1 nivel, los managers 2, los coordinadores 3, los técnicos 4, los juniors 5... Power BI no sabe cómo manejar jerarquías de profundidad variable directamente. Ahí entran las funciones Padre-Hijo.
El problema en datos
TABLA 'Empleados':
| EmpleadoID | Nombre | ManagerID |
|---|---|---|
| E001 | Elena García | (vacío ← es la CEO) |
| E002 | Carlos López | E001 |
| E003 | Ana Martín | E001 |
| E004 | Pedro Ruiz | E002 |
| E005 | Laura Sanz | E002 |
| E006 | Miguel Torres | E003 |
| E007 | Sofia Pérez | E004 |
Jerarquía resultante
Elena García (CEO)
├── Carlos López
│ ├── Pedro Ruiz
│ │ └── Sofia Pérez
│ └── Laura Sanz
└── Ana Martín
└── Miguel Torres
El problema: la profundidad varía por rama (1, 2, 3, 4 niveles...).
La solución: convertir esta estructura recursiva en columnas fijas.
Otros casos de uso típicos
- Plan de cuentas contable — cuenta padre > subcuenta > subsubcuenta...
- Taxonomía de productos — categoría > subcategoría > familia > SKU
- Estructura organizativa — CEO > Director > Manager > Coordinador > Técnico
- BOM (Bill of Materials) — productos con componentes y subcomponentes
PATH — el punto de partida
Ejemplo básico:
// Columna calculada en la tabla Empleados:
'Empleados'[Path] = PATH('Empleados'[EmpleadoID], 'Empleados'[ManagerID])
// Resultado:
// Elena García (E001): "E001"
// Carlos López (E002): "E001|E002"
// Pedro Ruiz (E004): "E001|E002|E004"
// Sofia Pérez (E007): "E001|E002|E004|E007"
// ¡Importante! El campo ManagerID de la raíz (CEO) debe ser BLANK o el mismo ID
// Si tienes texto vacío "" en lugar de BLANK, conviértelo primero:
'Empleados'[ManagerIDLimpio] =
IF('Empleados'[ManagerID] = "", BLANK(), 'Empleados'[ManagerID])
'Empleados'[Path] =
PATH('Empleados'[EmpleadoID], 'Empleados'[ManagerIDLimpio])
Ejemplo plan de cuentas:
// Lo mismo para plan de cuentas:
'Cuentas'[Path] = PATH('Cuentas'[CuentaID], 'Cuentas'[CuentaPadreID])
PATHLENGTH — la profundidad
Ejemplo básico:
// Nivel de cada empleado en la jerarquía:
'Empleados'[Nivel] = PATHLENGTH('Empleados'[Path])
// Resultado:
// Elena García: Nivel 1 (la raíz)
// Carlos López: Nivel 2
// Pedro Ruiz: Nivel 3
// Sofia Pérez: Nivel 4
Ejemplo con nombres de nivel:
// Nombre del nivel:
'Empleados'[Nombre Nivel] =
SWITCH(
'Empleados'[Nivel],
1, "CEO / Dirección",
2, "Director",
3, "Manager",
4, "Coordinador",
5, "Técnico Senior",
"Junior"
)
Profundidad máxima:
// Profundidad máxima de la jerarquía:
Niveles Totales = MAXX(ALL('Empleados'), 'Empleados'[Nivel])
PATHITEM y PATHITEMREVERSE — extraer niveles
Ejemplo básico:
// Extraer el nivel 1 (la raíz — siempre es la CEO):
'Empleados'[Nivel1 ID] = PATHITEM('Empleados'[Path], 1)
// Siempre devuelve "E001" (Elena García) para todos los empleados
// Extraer el nivel 2 (director directo de la CEO):
'Empleados'[Nivel2 ID] = PATHITEM('Empleados'[Path], 2)
// Para Pedro Ruiz: "E002" (Carlos López)
// Para Elena García: BLANK (no tiene nivel 2)
Extraer el propio ID:
// Extraer el propio ID (último nivel = el propio nodo):
'Empleados'[Mi ID desde Path] =
PATHITEM('Empleados'[Path], PATHLENGTH('Empleados'[Path]))
Convertir ID a nombre:
// Usar LOOKUPVALUE para convertir ID en nombre:
'Empleados'[Nombre Nivel1] =
LOOKUPVALUE(
'Empleados'[Nombre],
'Empleados'[EmpleadoID],
PATHITEM('Empleados'[Path], 1)
)
Ejemplo básico:
// El propio empleado (posición 1 desde el final):
'Empleados'[Mi ID] = PATHITEMREVERSE('Empleados'[Path], 1)
// Siempre devuelve el propio EmpleadoID
// El manager directo (posición 2 desde el final):
'Empleados'[Manager Directo ID] = PATHITEMREVERSE('Empleados'[Path], 2)
// Si Sofia Pérez: devuelve "E004" (Pedro Ruiz, su manager)
// El "abuelo" en la jerarquía:
'Empleados'[Nivel -2 ID] = PATHITEMREVERSE('Empleados'[Path], 3)
Diferencia PATHITEM vs PATHITEMREVERSE:
// Para Sofia Pérez, Path = "E001|E002|E004|E007":
PATHITEM('Empleados'[Path], 1) → "E001" (Elena, la raíz)
PATHITEM('Empleados'[Path], 2) → "E002" (Carlos)
PATHITEM('Empleados'[Path], 3) → "E004" (Pedro)
PATHITEM('Empleados'[Path], 4) → "E007" (Sofia, ella misma)
PATHITEMREVERSE('Empleados'[Path], 1) → "E007" (Sofia, ella misma)
PATHITEMREVERSE('Empleados'[Path], 2) → "E004" (Pedro, su manager)
PATHITEMREVERSE('Empleados'[Path], 3) → "E002" (Carlos, su gran-manager)
PATHITEMREVERSE('Empleados'[Path], 4) → "E001" (Elena, la raíz)
PATHCONTAINS — verificar pertenencia
Ejemplo básico:
// ¿Es Carlos López (E002) un ancestro de Sofia Pérez?
Es Ancestro = PATHCONTAINS('Empleados'[Path], "E002")
// Para Sofia (Path = "E001|E002|E004|E007"): TRUE
// Para Miguel Torres (Path = "E001|E003|E006"): FALSE
Filtrar subordinados:
// Todos los subordinados directos e indirectos de Carlos López:
Equipo Carlos =
FILTER(
'Empleados',
PATHCONTAINS('Empleados'[Path], "E002")
&& 'Empleados'[EmpleadoID] <> "E002" -- excluir al propio Carlos
)
Ventas del equipo:
// Ventas del equipo de un manager (incluyendo todos sus subordinados):
Ventas Equipo =
CALCULATE(
SUM('Ventas'[Importe]),
FILTER(
'Empleados',
PATHCONTAINS(
'Empleados'[Path],
SELECTEDVALUE('Empleados'[EmpleadoID])
)
)
)
El patrón completo — aplanar la jerarquía
El patrón definitivo para trabajar con jerarquías padre-hijo en Power BI
Power BI necesita columnas fijas para hacer jerarquías visuales (como las que ves en una matriz expandible). El patrón estándar es convertir la jerarquía padre-hijo recursiva en N columnas fijas (una por nivel máximo de la jerarquía). Así Power BI puede hacer drill-down.
Paso 1 — Determinar la profundidad máxima
// Primero crea la columna Path:
'Empleados'[Path] = PATH('Empleados'[EmpleadoID], 'Empleados'[ManagerID])
// Luego la columna Nivel:
'Empleados'[Nivel] = PATHLENGTH('Empleados'[Path])
// Ver la profundidad máxima (para saber cuántas columnas necesitas):
// En DAX Studio: EVALUATE ROW("MaxNivel", MAXX(ALL('Empleados'), 'Empleados'[Nivel]))
Paso 2 — Crear columnas por nivel (asumiendo max 5 niveles)
// Columnas de ID por nivel:
'Empleados'[Nivel1 ID] = PATHITEM('Empleados'[Path], 1)
'Empleados'[Nivel2 ID] =
IF(PATHLENGTH('Empleados'[Path]) >= 2, PATHITEM('Empleados'[Path], 2), BLANK())
'Empleados'[Nivel3 ID] =
IF(PATHLENGTH('Empleados'[Path]) >= 3, PATHITEM('Empleados'[Path], 3), BLANK())
'Empleados'[Nivel4 ID] =
IF(PATHLENGTH('Empleados'[Path]) >= 4, PATHITEM('Empleados'[Path], 4), BLANK())
'Empleados'[Nivel5 ID] =
IF(PATHLENGTH('Empleados'[Path]) >= 5, PATHITEM('Empleados'[Path], 5), BLANK())
Paso 3 — Convertir IDs a nombres
// Columnas de Nombre por nivel (más útiles para visualización):
'Empleados'[Nivel1 Nombre] =
LOOKUPVALUE('Empleados'[Nombre], 'Empleados'[EmpleadoID], 'Empleados'[Nivel1 ID])
'Empleados'[Nivel2 Nombre] =
IF(NOT ISBLANK('Empleados'[Nivel2 ID]),
LOOKUPVALUE('Empleados'[Nombre], 'Empleados'[EmpleadoID], 'Empleados'[Nivel2 ID]),
BLANK())
'Empleados'[Nivel3 Nombre] =
IF(NOT ISBLANK('Empleados'[Nivel3 ID]),
LOOKUPVALUE('Empleados'[Nombre], 'Empleados'[EmpleadoID], 'Empleados'[Nivel3 ID]),
BLANK())
// ... repetir para Nivel4 y Nivel5
Paso 4 — Crear la jerarquía en Power BI
En el panel de Campos:
- → Clic derecho en 'Nivel1 Nombre' → "Crear jerarquía"
- → Arrastrar 'Nivel2 Nombre', 'Nivel3 Nombre'... a la jerarquía
- → Usar la jerarquía en una matriz con drill-down habilitado
Paso 5 — Medidas que respetan la jerarquía
// Esta medida funciona en cualquier nivel de la jerarquía:
Ventas Equipo =
SUMX(
FILTER(
ALL('Empleados'),
PATHCONTAINS(
'Empleados'[Path],
SELECTEDVALUE('Empleados'[EmpleadoID])
)
),
CALCULATE(SUM('Ventas'[Importe]))
)
Este es el patrón estándar que todo modelo con jerarquías padre-hijo debe seguir. Las columnas calculadas de Path, Nivel, y Nivel1-5 deben estar en la tabla fuente. Luego creas una jerarquía visual en Power BI para habilitar drill-down en matrices y visuales.
Casos de uso reales
Patrón 1 — Plan de cuentas contable
// Misma lógica pero con cuentas:
'Cuentas'[Path] = PATH('Cuentas'[CuentaID], 'Cuentas'[CuentaPadreID])
'Cuentas'[Nivel] = PATHLENGTH('Cuentas'[Path])
'Cuentas'[Cuenta Nivel1] = PATHITEM('Cuentas'[Path], 1) // Activo / Pasivo / Patrimonio
'Cuentas'[Cuenta Nivel2] =
IF(PATHLENGTH('Cuentas'[Path]) >= 2, PATHITEM('Cuentas'[Path], 2), BLANK())
'Cuentas'[Cuenta Nivel3] =
IF(PATHLENGTH('Cuentas'[Path]) >= 3, PATHITEM('Cuentas'[Path], 3), BLANK())
// Saldo acumulado (incluyendo todas las subcuentas hijas):
Saldo Acumulado =
CALCULATE(
SUM('Movimientos'[Importe]),
FILTER(
ALL('Cuentas'),
PATHCONTAINS('Cuentas'[Path], SELECTEDVALUE('Cuentas'[CuentaID]))
)
)
Patrón 2 — Headcount y organigrama
// Total de personas en el equipo de un manager (incluyendo todos los niveles):
Headcount Total =
COUNTROWS(
FILTER(
ALL('Empleados'),
PATHCONTAINS('Empleados'[Path], SELECTEDVALUE('Empleados'[EmpleadoID]))
&& 'Empleados'[EmpleadoID] <> SELECTEDVALUE('Empleados'[EmpleadoID])
)
)
// Manager con más personas a su cargo:
Manager Mayor Equipo =
MAXX(
ALL('Empleados'),
CALCULATE(
COUNTROWS(
FILTER(
ALL('Empleados'),
PATHCONTAINS('Empleados'[Path], 'Empleados'[EmpleadoID])
)
)
)
)
Patrón 3 — BOM (Bill of Materials) — coste total de un producto
// Tabla de componentes: ProductoID | ComponenteID | Cantidad | Coste
'Componentes'[Path] =
PATH('Componentes'[ComponenteID], 'Componentes'[ComponentePadreID])
// Coste total incluyendo todos los subcomponentes:
Coste Total BOM =
SUMX(
FILTER(
ALL('Componentes'),
PATHCONTAINS(
'Componentes'[Path],
SELECTEDVALUE('Componentes'[ComponenteID])
)
&& PATHLENGTH('Componentes'[Path]) = MAXX(
ALL('Componentes'),
PATHLENGTH('Componentes'[Path])
)
),
'Componentes'[Coste] * 'Componentes'[Cantidad]
)
¡Lo conseguiste! Has completado la guía más completa de funciones DAX en español. Desde SUM hasta PATH, pasando por CALCULATE, Window Functions, Visual Calculations y Grupos de Cálculo. Ahora tienes una referencia de cabecera para cualquier función DAX que necesites.
Recuerda: DAX se aprende usándolo. No te preocupes si no recuerdas todo — para eso está esta guía. Lo importante es saber que existe la función, qué hace y dónde buscarla cuando la necesites.
¡Tú puedes! 🌸🚀