Cálculo del número de valores previos a cada fecha

En este escenario partimos de la siguiente tabla de datos:

Tabla de datos

Obsérvese que en la tabla las fechas se muestran ordenadas (de más antiguas a más modernas) para hacer más sencilla su interpretación, pero tengamos en mente que podría no ser así.

El objetivo es crear una columna calculada que nos indique, para cada fila, cuántas filas de la misma tabla contienen fechas anteriores a la de la fila siendo considerada (teniendo en cuenta, como se ha comentado, que las filas podrían estar no ordenadas según la fecha).

Como queremos añadir una columna calculada, se va a crear por defecto un contexto de fila para cada una de las filas evaluadas. Es decir, para la primera fila (la correspondiente al campo Id 1) se creará un contexto de fila en el que podremos acceder a los valores de sus campos, Id y Date. A partir del valor del campo Date querríamos filtrar la tabla de forma que solo se considerasen las filas con fechas anteriores y contar el número de filas resultantes.

En pseudo código sería algo así:

Number of Previous values = 
COUNTROWS(
    FILTER(
        data,
        data[Date] < fecha-de-la-fila-actual
    )
)

Se ha utilizado la etiqueta fecha-de-la-fila-actual para hacer referencia al valor del campo Date de la fila siendo considerada.

La función FILTER, siendo un iterador, va a crear un nuevo contexto de fila en el que evaluar la condición para cada fila de la tabla data:

data[Date] < fecha-de-la-fila-actual

Lógicamente, el siguiente código no funcionaría:

Number of Previous values = 
COUNTROWS(
    FILTER(
        data,
        data[Date] < data[Date])
    )
)

...pues dentro del contexto de fila creado por FILTER, el valor de data[Date] es el valor del campo Date de la fila que FILTER esté iterando. Lo que querríamos es que el valor de fecha-de-la-fila-actual fuese el definido en el contexto de fila "anterior", el creado por la columna calculada previo a la ejecución de la función FILTER.

Para ello tenemos dos soluciones:

La primera -la única existente hasta que se introdujeron las variables en DAX en 2015- es recurrir a la función EARLIER. Esta función nos devuelve exactamente lo que queremos: el valor de un campo para un contexto de fila anterior (pudiendo indicarse cuántos contextos de fila hay que retroceder). Por ejemplo:

Number of Previous values = 
COUNTROWS(
    FILTER(
        data,
        data[Date] < EARLIER(data[Date], 1)
    )
)

...devolvería el resultado que buscábamos:

Función EARLIER

Vemos que, para la primera fila, la función devuelve un Blank pues no hay filas con fechas anteriores y la función COUNTROWS devuelve este valor para tablas vacías. Podemos forzar que, en este caso, se devuelva un 0 usando la función COALESCE:

Number of Previous values = 
COALESCE(
    COUNTROWS(
        FILTER(
            data,
            data[Date] < EARLIER(data[Date], 1)
        )
    ),
    0
)
Función EARLIER

En este caso, como el contexto "anterior" es el único contexto previo, también podríamos usar la función EARLIEST que nos devuelve el valor del campo indicado en el último contexto de fila existente:

Number of Previous values = 
COALESCE(
    COUNTROWS(
        FILTER(
            data,
            data[Date] < EARLIEST(data[Date])
        )
    ),
    0
)

El segundo método es, precisamente, haciendo uso de variables, lo que resulta mucho más sencillo y fácilmente interpretable. Concretamente:

Number of Previous values = 
VAR __currentDate = data[Date]
RETURN
    COUNTROWS(
        FILTER(
            data,
            data[Date] < __currentDate
        )
    )

En primer lugar creamos una variable (__currentDate) con la palabra reservada VAR. Esta variable se va a crear en el contexto de evaluación existente que, en ese punto del código, es el contexto de fila creado por la columna calculada. Es decir, en este punto, el campo data[Date] toma el valor del campo Date en la fila que se esté evaluando.

Una vez registrado el valor de la fecha se ejecuta el filtrado de la tabla data. Tal y como se ha comentado, la función FILTER crea un nuevo contexto de fila en el que se recorre la tabla en cuestión comparando cada valor del campo Date -evaluado en el contexto de fila de la función FILTER- con el valor registrado en la variable __currentDate (valor que se registró en el contexto de fila de la columna calculada):

Función EARLIER

Comprobamos que el resultado es el mismo que obtuvimos con la función EARLIER pero más fácil de interpretar.

Una vez más, podríamos usar la función COALESCE para forzar ceros allí donde COUNTROWS devuelva Blanks:

Number of Previous values = 
VAR __currentDate = data[Date]
RETURN
    COALESCE(
        COUNTROWS(
            FILTER(
                data,
                data[Date] < __currentDate
            )
        ),
        0
    )
Funciones DAX involucradas
Dificultad
Intermedia
Enviado por admin el Mié, 23/06/2021 - 15:10