Power BI · Capítulo 3 · Lección de conceptos · 7 min de lectura

La granularidad, y por qué un modelo tiene un solo camino

Toda tabla tiene una granularidad: la única cosa que representa una fila. Las relaciones siguen esa granularidad, y el modelo permite un solo camino activo entre dos tablas para que cada filtro tenga una sola ruta.

La idea

La granularidad (grain) de una tabla es lo que significa una fila. En orders una fila es un pedido. En order_items una fila es una línea de un pedido. En 'Date' una fila es un día del calendario. Antes de construir nada, debes poder terminar la frase "una fila de esta tabla es ..." sin ningún "o".

La granularidad parece vocabulario, pero es la regla detrás de casi todas las decisiones de modelado. Un número pertenece a la tabla cuya granularidad describe, y una relación conecta tablas cuyas granularidades encajan: muchas líneas en un pedido, muchos pedidos en un día.

Figura 1

Un valor del nivel de pedido, copiado en las líneas de pedido

orders: una fila por pedido
order_idshipping_fee
10034.99
10106.95
Copia plana: una fila por línea, con la tarifa repetida
order_item_idorder_idline_totalshipping_fee
8100383.694.99
91003314.104.99
23101011.996.95
24101026.996.95

Paso 1 de 4 orders tiene una fila por pedido, así que su granularidad es el pedido. Cada pedido tiene una tarifa de envío: $4.99 y $6.95, $11.94 en total.

  1. orders tiene una fila por pedido, así que su granularidad es el pedido. Cada pedido tiene una tarifa de envío: $4.99 y $6.95, $11.94 en total.
  2. Copia la tarifa en las líneas y la granularidad cambia a una fila por línea. El pedido 1003 tiene dos líneas, así que su tarifa ahora está escrita dos veces.
  3. SUM(shipping_fee) sobre la copia devuelve $23.88 en lugar de $11.94. Los datos no están mal. La suma cuenta una vez por línea un número que es del nivel de pedido.
  4. En el modelo, shipping_fee se queda en orders y se suma sobre una fila por pedido. La relación lleva el filtro y ningún número se repite.

Por qué existe

Un modelo que ignora la granularidad da totales erróneos sin dar ningún error. Power BI suma encantado cualquier columna que le des. Si un valor que pertenece a un pedido está en cada línea de ese pedido, la suma lo cuenta una vez por línea. Los ingresos se inflan, el informe se ve bien y el gerente decide con un número que nadie comprobó.

Declarar la granularidad también te dice en qué tabla va una columna nueva. La tarifa de envío describe el pedido, así que vive en orders. La quantity de una línea describe la línea, así que vive en order_items. Cuando una columna cabe en dos tablas, es que aún no has decidido la granularidad de una de ellas.

Cómo funciona por dentro

Nombra la granularidad y luego relaciona

Hazle la pregunta de la granularidad a cada tabla del modelo y escríbela:

Tabla Una fila es Rol
order_items un producto en un pedido hechos
orders un pedido cabecera, relaciona las dimensiones
products un producto dimensión
customers un cliente dimensión
'Date' un día del calendario dimensión

Una relación siempre une una granularidad más gruesa (el lado 1) con una más fina (el lado muchos). Una relación entre dos tablas con la misma granularidad es de uno a uno, lo que normalmente significa que deberían ser una sola tabla. Dos tablas que son "muchos" una de la otra son muchos a muchos, y eso indica que falta una dimensión entre ellas.

Qué comprueba el motor

Cuando creas una relación en Model view (Home → Manage relationships → New), Power BI comprueba que el lado 1 no tenga la clave repetida. Una clave duplicada en el supuesto lado 1 significa que la granularidad no es la que pensabas, y la relación se rechaza o se vuelve de muchos a muchos. Arregla la granularidad (quita duplicados o busca la clave real); no cambies la cardinalidad para que desaparezca el error.

Un solo camino activo

Entre dos tablas cualesquiera, el modelo permite un solo camino activo. Los filtros siguen las relaciones activas y nada más. Si existieran dos caminos, un filtro podría llegar a una tabla por las dos rutas y la respuesta dependería de cuál eligiera el motor.

Figura 2

Dos relaciones desde 'Date', una de ellas inactiva

'Date'

  • Date
  • Year
  • Month

Year = 2025

orders

  • order_id
  • customer_id
  • order_date

customers

  • customer_id
  • signup_date
  • segment

order_items

  • order_item_id
  • order_id
  • line_total

Paso 1 de 4 Las ventas dependen de la fecha del pedido, así que 'Date'[Date] se relaciona con orders[order_date]. Una segmentación de Year filtra 'Date', y el filtro fluye a orders y order_items.

  1. Las ventas dependen de la fecha del pedido, así que 'Date'[Date] se relaciona con orders[order_date]. Una segmentación de Year filtra 'Date', y el filtro fluye a orders y order_items.
  2. Marketing también quiere altas por mes, a partir de customers[signup_date]. Es una segunda fecha, así que hace falta una segunda relación con el mismo calendario. Se dibuja punteada: inactiva.
  3. Si estuviera activa, un filtro de Year llegaría a orders por dos caminos: directo y a través de customers. Los dos podrían dar conjuntos de pedidos distintos, así que Power BI no lo permite.
  4. Una relación inactiva duerme hasta que una medida la llama: CALCULATE([Customers], USERELATIONSHIP(customers[signup_date], 'Date'[Date])) la activa solo para esa medida.

Por eso una segunda fecha tiene que ser inactiva. Harbor & Pine tiene dos fechas que significan cosas distintas: cuándo se hizo un pedido y cuándo se dio de alta un cliente. Ambas se relacionan con la misma tabla 'Date'. La relación de la fecha del pedido es activa porque las ventas son la historia principal. La relación de la fecha de alta es inactiva, se dibuja punteada, y una medida la activa de forma explícita con USERELATIONSHIP. En el cuadro Edit relationship la casilla se llama Make this relationship active.

El mismo calendario juega dos papeles, lo que se llama una dimensión de rol múltiple (role-playing dimension). Mantienes una sola tabla 'Date', con todas sus columnas, y dejas que distintas relaciones la usen. La alternativa, una copia del calendario por cada fecha, duplica el mantenimiento y divide las segmentaciones.

Marca el calendario

Una regla más va aquí. En una tabla 'Date', usa Table tools → Mark as date table y elige la columna Date. Eso le dice a DAX cuál es la columna del calendario, y desbloquea la inteligencia de tiempo de los próximos capítulos. La tabla debe tener una fila por día, sin huecos, desde la primera fecha de pedido hasta la última.

Las jerarquías también se apoyan en la granularidad

Una jerarquía (hierarchy) es un camino ordenado por columnas de una dimensión, como Year, Quarter, Month, Date. Créala en el panel Data (clic derecho en una columna, Create hierarchy) y un gráfico puede bajar de año a mes con un clic. Solo funciona porque cada nivel encaja en el siguiente: un mes pertenece a un año. Una columna que no encaja, como el día de la semana, no pertenece a esa jerarquía. Además, los nombres de mes se ordenan alfabéticamente salvo que uses Sort by column con el número de mes.

Errores comunes

"El filtrado bidireccional arregla cualquier problema del modelo"

Una relación en Both deja que los filtros suban también del lado muchos al lado uno. Parece una cura cuando una segmentación no llega a una tabla, y a menudo es la causa del siguiente error: más caminos, visuales más lentos, ambigüedad. Antes pregúntate si la segmentación está en la tabla correcta. La estrella normalmente necesita dirección única, de las dimensiones a los hechos.

"Si un total parece razonable, la granularidad es la correcta"

Un valor repetido no rompe nada a la vista. Cada visual sigue dibujando un número; solo que es demasiado alto. Nada lo señala. La comprobación es sumar la columna con su propia granularidad, aquí los $11.94 de orders, y compararla con la misma medida en un visual. Si difieren, se está contando un valor más de una vez.

"Dos relaciones entre las mismas tablas son un error"

Están bien mientras como máximo una sea activa. Que una fecha juegue varios papeles es la razón más común para tener dos. Power BI mismo crea la segunda como inactiva cuando detecta relaciones automáticamente. El error son dos caminos activos, no dos relaciones.

Ponte a prueba

Una pregunta. Al responderla, la lección queda marcada en el mapa; nunca bloquea un nivel.

orders[shipping_fee] es un valor por pedido. Un colega lo une a las líneas de pedido para que cada línea lleve la tarifa de su pedido, y luego suma la columna. El pedido 1003 tiene dos líneas y una tarifa de $4.99. ¿Qué sale mal?

Elige qué puede ejecutarse en este sitio. Puedes cambiarlo cuando quieras desde "Configurar cookies", al pie de cada página.