Calculation of the number of values prior to each date

In this scenario we start from the following data table:

Tabla de datos

Note that in the table the dates are shown in order (from oldest to most modern) to make their interpretation easier, but keep in mind that this might not be the case.

The objective is to create a calculated column that tells us, for each row, how many rows of the same table contain dates prior to the one of the row being considered (taking into account, as has been commented, that the rows could be not ordered according to the date).

As we want to add a calculated column, a row context will be created by default for each of the evaluated rows. That is, for the first row (the one corresponding to the field Id 1) a row context will be created in which we can access the values of its fields, Id and Date. From the value of the Date field we would like to filter the table so that only the rows with previous dates are considered, and count the number of resulting rows.

In pseudo code it would be something like this:

Number of Previous values = 
COUNTROWS(
    FILTER(
        data,
        data[Date] < current-row-date
    )
)

The current-row-date tag has been used to refer to the value of the Date field of the row being considered.

The FILTER function, being an iterator, will create a new row context in which to evaluate the condition for each row of the data table:

data[Date] < current-row-date

Logically, the following code would not work:

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

...because within the row context created by FILTER, the value of data[Date] is the value of the Date field of the row that FILTER is iterating. What we would like is for the current-row-date value to be the one defined in the "previous" row context, the one created by the calculated column prior to executing the FILTER function.

For this we have two solutions:

The first -the only one that existed until the variables were introduced in DAX in 2015- is to use the EARLIER function. This function returns exactly what we want: the value of a field for a previous row context (allowing us to indicate how many row contexts to go back). For example:

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

...would return the result we were looking for:

Función EARLIER

We see that, for the first row, the function returns a Blank since there are no rows with previous dates and the COUNTROWS function returns this value for empty tables. We can force a 0 to be returned in this case using the COALESCE function:

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

In this case, as the "previous" context is the only previous context, we could also use the EARLIEST function that returns the value of the field indicated in the last existing row context:

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

The second method is precisely by making use of variables, which is much simpler and easier to interpret. Specifically:

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

First we create a variable (__currentDate) with the VAR keyword. This variable will be created in the existing evaluation context which, at that point in the code, is the row context created by the calculated column. That is, at this point, the data[Date] field takes the value of the Date field in the row being evaluated.

Once the date has been registered, the filtering of the data table is executed. As mentioned, the FILTER function creates a new row context in which the table in question is iterated, comparing each value of the Date field -evaluated in the row context of the FILTER function- with the value registered in the variable __currentDate (value that was defined in the row context of the calculated column):

Función EARLIER

We can see that the result is the same as that obtained with the EARLIER function but easier to interpret.

Once again, we could use the COALESCE function to force zeros where COUNTROWS returns Blanks:

Number of Previous values = 
VAR __currentDate = data[Date]
RETURN
    COALESCE(
        COUNTROWS(
            FILTER(
                data,
                data[Date] < __currentDate
            )
        ),
        0
    )
DAX functions involved
Difficulty
Intermediate
Submitted by admin on Wed, 06/23/2021 - 15:10