Running Total

A general DAX pattern for calculating running (cumulative) totals over any sorted column, not just dates.

Running Total

A running total adds each row to the sum of everything before it.

Month     | Sales   | Running Total
----------|---------|---------------
January   | 50,000  | 50,000
February  | 60,000  | 110,000
March     | 45,000  | 155,000

Time-based running totals (like Year-to-Date) have dedicated DAX functions — see Time Intelligence. This page covers the general pattern, which works over any sortable column, not just dates.


The General Pattern

Running Total =
CALCULATE(
    [Total Sales],
    FILTER(
        ALL(DimDate[Date]),
        DimDate[Date] <= MAX(DimDate[Date])
    )
)
FILTER(
   ALL(DimDate[Date]),              all dates, filters removed
   DimDate[Date] <= MAX(DimDate[Date])   keep only dates up to the current row
)

MAX(DimDate[Date]) picks up the current row's date from context. FILTER() keeps every date less than or equal to it. ALL() makes sure the comparison set isn't limited to whatever's already been filtered.

Anatomy of a running total

Running Total = CALCULATE([Total Sales], FILTER(ALL(DimDate[Date]), DimDate[Date] <= MAX(DimDate[Date]) ))

Evaluating the Feb '26 row of the visual

1ALL() reopens the dates

Visual context: Feb '26 only → ALL(): all 5 months

2MAX() reads the row

Evaluated in the visual's context, not ALL()'s: Feb '26

3<= keeps the past

4 of 5 dates survive: 40 + 35 + 50 + 60

✓$185K

Running Total — every visual row

RowNov25Dec25Jan26Feb26Mar26Total
Nov '25
40
·
·
·
·
$40K
Dec '25
40
35
·
·
·
$75K
Jan '26
40
35
50
·
·
$125K
Feb '26
40
35
50
60
·
$185K
Mar '26
40
35
50
60
45
$230K

4Within Year — adds Year = MAX(Year)

RowNov25Dec25Jan26Feb26Mar26Total
Nov '25
40
·
·
·
·
$40K
Dec '25
40
35
·
·
·
$75K
Jan '26
·
·
50
·
·
$50K
Feb '26
·
·
50
60
·
$110K
Mar '26
·
·
50
60
45
$155K
1

ALL(DimDate[Date]) — the visual row has already filtered the dates down to one month. ALL() hands FILTER() every date instead. Without it, FILTER() only sees Feb '26, and the "running total" is just that month's $60K.

2

MAX(DimDate[Date]) — the outlined cell in each row. It runs inside FILTER()'s row loop, but row context doesn't filter anything, and ALL() only shaped FILTER()'s input table, not the filter context. So MAX() still sees the visual's filter and returns the current row's date, not the last date in the table.

3

<= — tested against every date ALL() returned, so each row keeps one more month than the row above it. The grey cells were scanned and rejected: 5 rows × 5 dates = 25 comparisons here, which is why this pattern slows down on long date columns.

4

&& DimDate[Year] = MAX(DimDate[Year]) — a second condition that rejects earlier years too. The staircase restarts in January, so Feb '26 keeps only Jan + Feb = $110K instead of $185K.

✓

Result — CALCULATE() replaces the visual's date filter with the surviving dates and evaluates [Total Sales] over them.


Running Total Over Any Sorted Value

The same pattern works over a rank or sequence number, not just a date.

Running Total by Rank =
CALCULATE(
    [Total Sales],
    FILTER(
        ALL(DimProduct[SalesRank]),
        DimProduct[SalesRank] <= MAX(DimProduct[SalesRank])
    )
)

Useful for cumulative charts like "what percentage of total sales come from the top N products" (a Pareto / 80-20 analysis).


Running Total Within a Group

Restarting the running total for each group (like each year) combines the pattern with a group-preserving filter.

Running Total Within Year =
CALCULATE(
    [Total Sales],
    FILTER(
        ALL(DimDate[Date]),
        DimDate[Date] <= MAX(DimDate[Date]) &&
        DimDate[Year] = MAX(DimDate[Year])
    )
)
Year | Month     | Sales   | Running Total
-----|-----------|---------|---------------
2025 | November  | 40,000  | 40,000
2025 | December  | 35,000  | 75,000
2026 | January   | 50,000  | 50,000
2026 | February  | 60,000  | 110,000

The running total resets at the start of each year, instead of accumulating across the entire date range.


Running Total Using Time Intelligence Functions

For calendar-based running totals specifically, TOTALYTD(), TOTALQTD(), and TOTALMTD() are simpler and more efficient than the generic FILTER() pattern.

Sales YTD =
TOTALYTD(
    [Total Sales],
    DimDate[Date]
)

Use the generic FILTER()-based pattern when the running total isn't calendar-based — ranks, sequence numbers, or any other sortable column where the built-in time intelligence functions don't apply.

The Time Intelligence Generator writes both versions for your own measure: year-to-date with the time intelligence functions, and an all-time running total with the FILTER() pattern.


Performance Considerations

The FILTER(ALL(...), ...) pattern re-evaluates across the full unfiltered column for every row, which can be slow on very large date or rank columns.

Rows evaluated per cell = size of the unfiltered column

For calendar dates specifically, TOTALYTD() and related functions are generally faster, since they're optimized internally rather than relying on a generic row-by-row filter scan.


Best Practices

  • Use dedicated time intelligence functions (TOTALYTD(), etc.) for calendar-based running totals.
  • Reserve the FILTER(ALL(...), ...) pattern for running totals over non-date columns.
  • Test running total measures against a large, realistic dataset — this pattern's performance degrades with column size.
  • Add a group condition (like Year) when the running total should reset periodically instead of accumulating indefinitely.

Common Mistakes

Using FILTER(ALL()) for Simple Date Running Totals

When the running total is just Year-to-Date or similar, TOTALYTD() does the same job more efficiently and more clearly than the generic pattern.

Forgetting to Reset Within Groups

A running total that should restart each year, but doesn't include the year condition in the FILTER(), will keep accumulating across year boundaries instead of resetting.

Sorting Assumptions

The pattern depends on comparing values with <=. If the column being compared isn't naturally ordered the way the business expects (like a text field instead of a number or date), the "running total" won't make sense.


Running Total Checklist

Before publishing a running total measure:

  • Calendar-based running totals use TOTALYTD()/TOTALQTD()/TOTALMTD() where possible.
  • Non-date running totals correctly use FILTER(ALL(...), ...) over a genuinely sortable column.
  • Group resets (like per-year) are included if the business logic requires them.
  • Performance has been tested against production-scale data.

Next Steps

Continue exploring DAX patterns: