En este escenario partimos de la siguiente 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í:
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:
Lógicamente, el siguiente código no funcionaría:
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:
COUNTROWS(
FILTER(
data,
data[Date] < EARLIER(data[Date], 1)
)
)
...devolvería el resultado que buscábamos:
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:
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < EARLIER(data[Date], 1)
)
),
0
)
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:
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:
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):
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:
VAR __currentDate = data[Date]
RETURN
COALESCE(
COUNTROWS(
FILTER(
data,
data[Date] < __currentDate
)
),
0
)