Tableau Migration Table Calculations DAX

Tableau Table Calculations to DAX: Running Totals, Ranks, and Window Functions

July 27, 2026

Tableau table calculations run on the result set after aggregation, using the layout of the view to define direction and scope. DAX has no result set to walk, so every conversion rebuilds "Compute Using" as an explicit filter or window definition. The classic approach wraps CALCULATE around a FILTER. Newer DAX window functions (OFFSET, WINDOW, ROWNUMBER) express the same logic more directly where your Power BI version supports them.

Table calculation to DAX conversion table

TableauDAX equivalentApproach
RUNNING_SUM(SUM([Sales]))CALCULATE(SUM(Sales[Amount]), FILTER(ALLSELECTED('Date'[Date]), 'Date'[Date] <= MAX('Date'[Date])))Cumulative filter
WINDOW_AVG(SUM([Sales]))AVERAGEX(ALLSELECTED('Date'[Month]), CALCULATE(SUM(Sales[Amount])))Iterate the partition
WINDOW_AVG(SUM([Sales]), -2, 0)AVERAGEX(WINDOW(-2, REL, 0, REL, …), CALCULATE(SUM(Sales[Amount])))Window function
TOTAL(SUM([Sales]))CALCULATE(SUM(Sales[Amount]), ALLSELECTED())Whole-partition total
RANK(SUM([Sales]))RANKX(ALLSELECTED(Product[Product]), CALCULATE(SUM(Sales[Amount])))Ranking
INDEX()ROWNUMBER(ALLSELECTED(…), ORDERBY(…))Positional
SIZE()COUNTROWS(ALLSELECTED(Product[Product]))Positional
LOOKUP(SUM([Sales]), -1)CALCULATE(SUM(Sales[Amount]), OFFSET(-1, ALLSELECTED('Date'[Month]), ORDERBY('Date'[Month])))Offset
PERCENT_OF_TOTAL(SUM([Sales]))DIVIDE(SUM(Sales[Amount]), CALCULATE(SUM(Sales[Amount]), ALLSELECTED(Product[Product])))Ratio to partition
PREVIOUS_VALUE()Recursive; no DAX equivalent

Running totals and moving averages

A running total is a cumulative filter: sum everything up to and including the current row's position on the axis. Two details decide whether it matches Tableau. Use ALLSELECTED rather than ALL, so the running total stays inside the user's slicer selection the way Tableau's default addressing does. And read the current position with MAX('Date'[Date]) — that idiom stands in for "the current row" when there is no row context. If the Tableau calculation restarts on a dimension ("Restarting every Year"), add that column back as a filter argument so it survives ALLSELECTED.

Moving averages need a bounded window rather than an open-ended one. The WINDOW function takes relative or absolute boundaries plus an explicit sort, so WINDOW(-2, REL, 0, REL, …) is the direct equivalent of Tableau's -2, 0 offsets. Without window functions, the equivalent is AVERAGEX over DATESINPERIOD, which requires a date table. With no offsets at all, the window is the whole partition and the conversion collapses to an iterator over ALLSELECTED — the same shape covers WINDOW_SUM, WINDOW_MIN, WINDOW_MAX, and WINDOW_MEDIAN.

Ranks and positions

Tableau's five ranking functions differ mainly in how they treat ties, and RANKX covers most of them through its optional ties argument. Note that DAX has its own functions called RANK and INDEX; neither is the equivalent of the Tableau function with the same name. Both languages rank from the highest value down by default, and Skip ties are the RANKX default, so the plain form already matches Tableau's RANK. Watch the direction on RANK_PERCENTILE, though: Tableau puts the lowest value at 0 and the highest at 1, which is the reverse of a descending rank.

TableauTies produceDAX
RANK1, 2, 2, 4RANKX(…)Skip is the default
RANK_DENSE1, 2, 2, 3RANKX(table, expr, , , "Dense")ties is the fifth argument
RANK_UNIQUE1, 2, 3, 4ROWNUMBER(…, ORDERBY(…))
RANK_MODIFIED1, 3, 3, 4No direct form — derive from RANKX and the tie count
RANK_PERCENTILE0–1 scale, lowest value is 0DIVIDE(COUNTROWS(ALLSELECTED(…)) - RANKX(…), COUNTROWS(ALLSELECTED(…)) - 1)

INDEX() returns a position in the addressing order rather than a rank by value, so its equivalent is ROWNUMBER, not RANKX. From there, SIZE() is COUNTROWS(ALLSELECTED(…)), FIRST() is 1 - ROWNUMBER(…), and LAST() is COUNTROWS(ALLSELECTED(…)) - ROWNUMBER(…).

LOOKUP and PREVIOUS_VALUE

LOOKUP fetches a value from another position in the partition, and OFFSET is the direct translation. When the offset is genuinely a time shift and a proper date table exists, time intelligence is clearer and faster — PREVIOUSMONTH or DATEADD. The difference matters when periods are missing from the data: OFFSET steps to the previous row that exists, time intelligence steps to the previous calendar month whether or not it has data.

PREVIOUS_VALUE() has no DAX equivalent. It is recursive by nature: each row reads the calculation's own output from the row before it, and a DAX measure cannot reference its own prior result. Every occurrence needs restructuring, usually into a running aggregate or a Power Query step that materialises the sequence at load time. These are the most expensive items in a table-calculation inventory and should be scoped separately.

Compute Using: addressing and partitioning in DAX

The Compute Using dialog is the whole configuration of a table calculation, and it is not stored in the formula text. Two calculations with identical text return different numbers if their addressing differs, which is why reading formulas alone is not enough to plan this work — you have to open the workbook.

Tableau conceptWhat it controlsDAX equivalent
Addressing (Compute Using)The direction the calculation movesORDERBY()
Partitioning (Restarting every)Where the calculation resetsPARTITIONBY()
Table (across)Walk columns, reset per rowORDERBY on the column field, PARTITIONBY on the row field
Table (down)Walk rows, reset per columnThe reverse pairing
Specific dimensionsAn explicit list, with a sort orderORDERBY plus PARTITIONBY naming those columns
Pane versus Table scopeWhether an outer dimension resets itAdd the outer column to PARTITIONBY, or leave it out

What Antares does with table calculations

Table calculations are not auto-converted — they are reported as manual DAX work, alongside LOD expressions and the other structural blockers. What the Analyzer does is inventory them precisely: each one is identified by kind, so a running total is not counted the same as a recursive calculation. It also detects Quick Table Calcs, which never appear as function names in the formula text and are therefore missed by any count based on searching formulas.

That distinction is what makes an estimate defensible. A workbook with thirty running totals is a day of mechanical work; a workbook with three PREVIOUS_VALUE calculations is a modelling problem. Both look identical in a raw formula count. Run the free Analyzer to get the breakdown for your own estate.

Related reading: Tableau LOD expressions to DAX and Tableau calculated fields to DAX. Primary sources: Tableau's table calculation function reference and Microsoft's DAX function reference.

← Back to Complete Migration Guide

Related Migration Resources

Frequently asked questions

What is the DAX equivalent of RUNNING_SUM?

A cumulative filter: CALCULATE(SUM(Sales[Amount]), FILTER(ALLSELECTED('Date'[Date]), 'Date'[Date] <= MAX('Date'[Date]))). ALLSELECTED keeps the running total inside the user's slicer selection, matching Tableau's default addressing, and MAX('Date'[Date]) stands in for the current row's position.

What is the DAX equivalent of Tableau's Compute Using setting?

ORDERBY and PARTITIONBY. Addressing — the direction a calculation moves — becomes ORDERBY; partitioning, or Restarting every, becomes PARTITIONBY. Compute Using is not stored in the formula text, so two identical Tableau formulas can return different numbers and must be inspected in the workbook.

Can PREVIOUS_VALUE be converted to DAX?

No. PREVIOUS_VALUE is recursive — each row reads the calculation's own output from the previous row — and a DAX measure cannot reference its own prior result. Every occurrence needs restructuring, usually into a running aggregate or a Power Query step that materialises the sequence at load time.

Does Antares convert Tableau table calculations automatically?

No — they are reported as manual DAX work. What the Analyzer does is inventory them by kind, so a running total is not counted the same as a recursive calculation, and it detects Quick Table Calcs, which never appear as function names in the formula text and are missed by any count based on searching formulas.

Let's talk migration.

Get your free Migration Readiness Score, or talk to our team about end-to-end delivery.