ANTERIORES vs ANTICIPADOS en DAX

Share on facebook
Share on twitter
Share on linkedin
Share on telegram
Share on whatsapp

Contenidos

Nivel: Avanzado

Las funciones EARLIER () y EARLIEST () son 2 de las funciones más difíciles de entender en DAX. Si tiene experiencia en programación, probablemente le resultará fácil. Sin embargo, como he dicho repetidamente en mi blog, una de las muchas cosas buenas de Power BI es que es accesible para simples usuarios mortales de Excel como tú y yo. No es necesario ser un programador de TI con formación clásica para ser un autor de informes de Power BI. Inevitablemente, sin embargo, habrá conceptos más difíciles que de hecho necesitará aprender si desea progresar de un principiante a un usuario intermedio o avanzado.

Data de muestra

Para este blog, usaré mi base de datos de Adventure Works simplificada para ver algunas ideas sobre las compras totales de los clientes y el valor del cliente. Para este blog voy a escribir algunas columnas calculadas que no son necesariamente las mejores prácticas, ni estas fórmulas son necesariamente la mejor manera de resolver el problema. Estos ejemplos están pensados ​​para demostrar los conceptos de EARLIER y EARLIEST únicamente.

Hay una tabla de Clientes que contiene todos los clientes únicos (identificados de forma única por la Clave de Cliente) y hay una tabla de ventas que contiene todos los registros de ventas de cada cliente. Existe una relación de uno a muchos entre las tablas.

image_thumb-32-7536332

Contexto de fila

El contexto de fila es el término en DAX que significa «evaluación fila por fila». En pocas palabras, significa que la misma fórmula se ejecuta una fila a la vez para devolver un resultado (potencialmente diferente) para cada fila. Existe un contexto de fila dentro de todas las columnas calculadas y también dentro de algunas funciones especiales de DAX como FILTER (), SUMX (), RANKX (), etc. Tomemos un ejemplo simple usando Adventure Works.

Tengo la siguiente medida

Total Sales = SUM(Sales[ExtendedAmount])

Cuando agrego esta medida en una nueva columna calculada en la tabla Cliente, obtengo el siguiente resultado (una nueva columna calculada llamada Cliente[Total Customer Sales]).

image_thumb-33-7143320

A pesar de que solo hay una fórmula DAX (mostrada como 1 arriba), hay muchas respuestas diferentes devueltas a la columna (mostrada como 2 arriba). La explicación simple es que la fórmula se ejecuta una fila a la vez y cada resultado se almacena en la nueva columna. La explicación más técnica es esta:

  1. Una columna calculada tiene un contexto de fila. Por lo tanto, cada fila se evaluará una a la vez.
  2. Se selecciona la primera fila en el contexto de la fila.
  3. [Total Sales] es una medida y tiene un CALCULAR implícito. El CALCULATE implícito convierte el contexto de fila en un contexto de filtro equivalente. Ahora hay un contexto de fila Y y un contexto de filtro.
  4. Debido al CALCULATE implícito, el contexto de filtro en el cliente único se propaga a través de la relación de un lado al lado de muchos.
  5. La tabla de Ventas ahora tiene un filtro aplicado para que solo existan ventas para este cliente en la copia filtrada de la tabla de Ventas.
  6. La medida [Total Sales] luego se ejecuta y suma todas las ventas de ese cliente.
  7. El resultado se almacena en la fila 1 de la nueva columna.
  8. Los pasos 2 a 7 se repiten para cada fila en el contexto de fila creado en el paso 1.

super-charge-power-bi-ad_1-1024x128-6595595

Contextos de filas anidadas

Una vez que tenga claro lo que hace un contexto de fila, es de esperar que pueda imaginar que es posible tener múltiples contextos de fila anidados dentro de una fórmula. Tomemos otro ejemplo ahora clasificando a los clientes en función de sus Ventas Totales. Aquí está la fórmula.

Customer Rank = RANKX(Customers, [Total Sales])

Y aquí está el resultado que muestra la nueva columna.

image_thumb-34-1149915

La explicación simple de cómo funciona esta fórmula es la siguiente. Primero calcula las ventas totales de cada cliente y luego clasifica a los clientes en función de esas ventas. Una explicación más técnica es que ahora hay 2 contextos de fila anidados, un contexto de fila interna (RANKX) y un contexto de fila externa (columna calculada). El contexto de la fila interior se ejecuta para cada una de las filas exteriores como se ilustra a continuación.

nested_thumb-3266705

La descripción técnica completa de cómo funciona es la siguiente.

    1. Una columna calculada tiene un contexto de fila. Por tanto, cada fila será
      evaluado una fila a la vez.
    2. Se selecciona la primera fila de la tabla de clientes en la columna calculada.
    3. La función RANKX también tiene un contexto de fila sobre la tabla de clientes. Ahora hay 2 contextos de fila, el primero creado por la columna calculada (exterior) y el segundo creado por RANKX (interior).
      • RANKX va a la primera fila del contexto de la fila interior. No sucederá nada más con el contexto de la fila exterior hasta que RANKX termine su trabajo. En esta etapa, la función RANKX está tratando de averiguar cómo se compara (clasifica) este único cliente actual (el identificado por el contexto de la fila exterior) con todos los demás clientes. Pero no puede hacer esto a menos que conozca las ventas totales de todos y cada uno de los clientes. Por lo tanto, tiene que trabajar en toda la tabla de Clientes y calcular las ventas totales de cada cliente antes de poder clasificarlos.
      • [Total Sales] es una medida y tiene un CALCULAR implícito. El CALCULATE implícito convierte el contexto de la fila interna en un contexto de filtro equivalente. Ahora hay contextos de 2 filas Y y un contexto de filtro.
      • RANKX repite el proceso de calcular las ventas para cada cliente en la tabla de clientes.
      • Una vez que ha evaluado las ventas totales de cada cliente, RANKX determina dónde se ubica este único cliente (el identificado por el contexto de la fila exterior) en comparación con todos los clientes.
    4. El proceso se repite para cada fila en el contexto de la fila exterior.
    5. La columna calculada devuelve y almacena la clasificación de cada cliente en la columna final.

Clasificación de clientes Versión de FILTRO

Otra forma (manual) de clasificar a los clientes es contar cuántos clientes tienen más ventas que el cliente seleccionado. Por ejemplo, el cliente más grande no tendrá otros clientes con más ventas, el segundo cliente más grande tendrá 1 cliente con más ventas, etc.

Si intentara escribir esta fórmula en pseudocódigo, podría verse así.

Customer Rank FILTER = 
        COUNTROWS(
           FILTER(Customers,
             Customers[Total Customer Sales] > 
                 'sales of the current customer being considered'
           )
        )

La fórmula anterior tiene 2 contextos de fila anidados, uno de la columna calculada y un segundo de la función FILTRO. La forma en que funciona la fórmula es la siguiente.

  1. La columna calculada crea un contexto de fila.
  2. Se selecciona el primer cliente
  3. La función FILTRO crea un contexto de segunda fila (interior).
  4. La función FILTRO trabaja a través de cada cliente en el contexto de la fila interior para determinar qué clientes tienen ventas mayores que el «cliente actual que se está considerando».

Pero, ¿cuál es el cliente actual que se considera en la prueba? Es el cliente del contexto de la fila exterior, por supuesto. Entonces, ¿cómo se puede escribir esta fórmula? Lo siguiente sería incorrecto.

Customer Rank FILTER = 
        COUNTROWS(
           FILTER(Customers,
             Customers[Total Customer Sales] > 
                 Customers[Total Customer Sales]
           )
        )

La fórmula anterior no puede funcionar porque la verificación de comparación dentro del FILTRO es incorrecta. La fórmula debe comparar las ventas totales del cliente en el contexto de la fila FILTRO (interior) con el cliente identificado en el contexto de la fila de la columna calculada (exterior). Esto es lo que hace la función EARLIER. Le dice a la fórmula que escape del contexto de la fila interior y vaya a buscar el valor del contexto de la fila anterior (exterior). Aquí está la fórmula correcta.

Customer Rank FILTER = 
        COUNTROWS(
           FILTER(Customers,
             Customers[Total Customer Sales] > 
                 EARLIER(Customers[Total Customer Sales])
           )
        ) + 1

Tenga en cuenta que tengo que agregar 1 al resultado final porque la fórmula sin procesar devolverá 0 clientes que tienen más ventas, por lo tanto, agregar 1 creará correctamente la clasificación a partir de 1.

Entonces, ¿qué pasa con EARLIEST?

La función EARLIER por defecto se refiere al contexto de fila que precedió inmediatamente al contexto de fila actual que se está considerando. En los ejemplos usados ​​aquí solo ha habido contextos de 2 filas, el externo y el interno. Dado que solo hay 2, cuando se usa EARLIER dentro del contexto de la fila interna, siempre se hace referencia al contexto de la fila externa. En este caso, EARLIER y EARLIEST se refieren al mismo contexto de fila exterior. Si hay más de 2 contextos de fila, la función EARLIER accede al contexto de fila anterior de forma predeterminada (comenzando desde el interior y moviéndose hacia afuera) y la función EARLIEST se refiere al contexto de fila más externo. ¿Pero sabías que EARLIER tiene un segundo parámetro opcional?

ANTES (, [number])

El segundo parámetro opcional es 1 por defecto (si se omite). Pero puede especificar qué tan atrás desea llegar a través de una serie de contextos de filas anidadas, como se ilustra a continuación.

img_5a4a0a7871e93-1976215

Ni siquiera puedo pensar en una fórmula de ejemplo para demostrar dónde el uso de EARLIER y EARLIEST devolverá un resultado diferente, pero supongo que es posible. Si puede pensar en uno, publíquelo en los comentarios y actualizaré este artículo en consecuencia.

!function(f,b,e,v,n,t,s)
{if(f.fbq)return;n=f.fbq=function(){n.callMethod?
n.callMethod.apply(n,arguments):n.queue.push(arguments)};
if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version=’2.0′;
n.queue=[];t=b.createElement(e);t.async=!0;
t.src=v;s=b.getElementsByTagName(e)[0];
s.parentNode.insertBefore(t,s)}(window,document,’script’,
‘https://connect.facebook.net/en_US/fbevents.js’);
fbq(‘init’, ‘639916389503636’);
fbq(‘track’, ‘PageView’);

Suscribite a nuestro Newsletter

No te enviaremos correo SPAM. Lo odiamos tanto como tú.