Tableau Migration LOD DAX Power BI

Tableau LOD Expressions to DAX: FIXED, INCLUDE, and EXCLUDE

October 14, 2026

Tableau Level of Detail (LOD) expressions have no one-to-one DAX equivalent, because Tableau controls aggregation grain with a keyword while Power BI controls it with filter context. Each keyword maps to a different DAX construct: FIXED becomes CALCULATE with ALLEXCEPT or REMOVEFILTERS, INCLUDE becomes an iterator such as AVERAGEX over VALUES, and EXCLUDE becomes CALCULATE with REMOVEFILTERS on the excluded column.

FIXED vs INCLUDE vs EXCLUDE

The three keywords differ in which dimensions set the grain of the calculation. Tableau's LOD documentation defines FIXED as computing with the named dimensions regardless of the view, INCLUDE as adding them to the dimensions already in the view, and EXCLUDE as subtracting them.

KeywordGrain of the resultDimension filtersReturns
FIXEDOnly the named dimensions, whatever the view showsIgnored, unless added to contextDimension or measure
INCLUDEThe view's dimensions plus the named ones, so finerApplied before itAlways a measure
EXCLUDEThe view's dimensions minus the named ones, so coarserApplied before itAlways a measure

The filter column is the one that shapes the DAX. FIXED is computed before dimension filters, while INCLUDE and EXCLUDE are computed after them, so the filters a FIXED expression ignored have to be cleared explicitly in DAX, while an EXCLUDE total still respects a filter on the excluded dimension — the reason the EXCLUDE section below reaches for ALLSELECTED.

Tableau LOD to DAX conversion table

Names below follow a standard star schema: a Sales fact table related to Customer, Product, and Geography dimensions.

Tableau LODDAX equivalentWhat it does
{FIXED [Region] : SUM([Sales])}CALCULATE(SUM(Sales[Amount]), ALLEXCEPT(Sales, Sales[Region]))Aggregates at Region, ignoring the view and dimension filters
{FIXED : SUM([Sales])}CALCULATE(SUM(Sales[Amount]), REMOVEFILTERS())Grand total, ignoring everything
SUM([Sales]) / MAX({FIXED [Region] : SUM([Sales])})DIVIDE(SUM(Sales[Amount]), CALCULATE(SUM(Sales[Amount]), ALLEXCEPT(Sales, Sales[Region])))Percent of a fixed total
{FIXED [Customer] : MIN([Order Date])}Calculated column on Customer: CALCULATE(MIN(Sales[OrderDate]))An attribute of an entity, not a measure
AVG({INCLUDE [Customer] : SUM([Sales])})AVERAGEX(VALUES(Customer[CustomerKey]), CALCULATE(SUM(Sales[Amount])))Aggregates below the view grain, then re-aggregates up
{EXCLUDE [Category] : SUM([Sales])}CALCULATE(SUM(Sales[Amount]), REMOVEFILTERS(Product[Category]))Aggregates above the view grain

How FIXED converts

FIXED pins aggregation to the dimensions you name and ignores everything else in the view. In DAX the equivalent move is to clear filter context from every column except the ones you want to keep, which is what ALLEXCEPT does.

There is one trap, and it accounts for most broken conversions. ALLEXCEPT(Sales, …) only clears filters on columns of the Sales table. A filter arriving from a related dimension table still propagates through the relationship, so a slicer on Product[Category] keeps shrinking the result even though the Tableau LOD ignored it. When the pinned dimension lives on a dimension table, combine REMOVEFILTERS() with VALUES(Geography[Region]) instead: the first clears the whole model, the second is evaluated in the outer filter context and puts the current region back.

It is also worth asking whether the LOD is a measure at all. A large share of FIXED expressions are attributes computed once per customer, order, or product — {FIXED [Customer] : MIN([Order Date])} is a cohort date. Modelled as a calculated column on the Customer table, CALCULATE(MIN(Sales[OrderDate])) is enough: inside a column, CALCULATE performs context transition and the relationship propagates the current customer. No ALLEXCEPT needed, and columns query faster than a measure re-evaluated per cell.

How INCLUDE converts

INCLUDE pushes aggregation below the grain of the view, then re-aggregates the result upward. The DAX equivalent is an iterator over the included dimension, and the rule is mechanical: an X iterator over VALUES of the included column, wrapping the inner aggregate in CALCULATE. Match the iterator to the outer aggregate — AVERAGEX for AVG, MAXX for MAX, MINX for MIN. The inner CALCULATE is not optional: it triggers the context transition that makes each iterated customer filter the fact table.

One shortcut worth knowing: if the outer aggregate is SUM, the INCLUDE is almost always redundant, because summing per-customer sums returns the same total. INCLUDE only changes the answer when the outer aggregate is non-additive — average, max, min, or distinct count.

How EXCLUDE converts

EXCLUDE drops a dimension that is present in the view, producing a coarser total on every row. In DAX you remove the filter on that one column and leave everything else alone.

If the excluded dimension is also on a slicer and the user's selection must still apply, use ALLSELECTED rather than REMOVEFILTERS — it restores the filter context from outside the visual instead of clearing it entirely. Note that ALL(Product[Category]) used as a CALCULATE filter argument does the same job as REMOVEFILTERS(Product[Category]); the latter is the newer, unambiguous name and reads better in review.

Why ALLEXCEPT does not always match FIXED

Tableau evaluates a worksheet through a fixed pipeline, and FIXED sits in the middle of it. DAX has no pipeline at all: there is only filter context, modified by CALCULATE. Reconciling the two is what makes LOD conversion hard, and it is why a formula-for-formula rewrite can look right and total wrong.

Tableau's order of operations resolves extract filters first, then data source filters, then context filters, then FIXED, then dimension filters, then INCLUDE and EXCLUDE. What matters for conversion is which filters land before FIXED and therefore still affect it:

Tableau filterAffects a FIXED LOD?How to reproduce in DAX
Data source / extract filterYesFilter the query in Power Query, not in the measure
Context filterYesALLSELECTED — keep what the user selected
Dimension filter (regular)NoALLEXCEPT or REMOVEFILTERS clears it
Measure filterNo — applied afterwardsFilter on the visual, not inside the measure

The practical rule: a workbook that leaned on context filters converts to ALLSELECTED, and one that leaned on ordinary dimension filters converts to ALLEXCEPT or REMOVEFILTERS. The LOD formula alone will not tell you which — you have to look at how the worksheet filtered. Testing a converted measure with and without a slicer applied is the check that catches the difference.

What Antares does with LOD expressions

On the Tableau to Power BI route, the Converter translates LOD expressions to DAX, deterministic-first. A short list of stereotyped shapes has one safe DAX template and is written without AI: a bare FIXED total, FIXED over a list of columns, a value divided by a FIXED total, an opening or closing value picked at the first or last date, a FIXED expression shifted by one period such as last year, and a simple EXCLUDE. Other LODs go to a guardrailed AI step that is held to the FIXED, INCLUDE and EXCLUDE patterns above and validated against the model before the result is kept. An LOD with no safe DAX shape, such as one whose dimension list depends on another measure, is not guessed at: it lands in the conversion report as a manual action with the reason, because a silently wrong rewrite costs far more to find in UAT than a flagged one costs to write by hand. Testing a converted measure with and without a slicer, as described above, is still the check to run.

Before any conversion, the free Analyzer finds them. Every calculated field in the workbook is parsed and classified, and each LOD is counted by type with the recommended DAX approach, so you know the LOD count and shape of an estate before committing to a date. Run the free Analyzer to get the breakdown for your own workbooks.

Related reading: Tableau calculated fields to DAX for the function-level mapping, and Tableau table calculations to DAX for RUNNING_SUM, WINDOW_AVG, and RANK. Primary sources: Tableau's LOD expression documentation and Microsoft's DAX function reference.

← Back to the Tableau to Power BI Migration guide

Related Migration Resources

Frequently asked questions

What is the difference between FIXED, INCLUDE and EXCLUDE?

They set the grain differently. FIXED uses only the dimensions you name and ignores the rest of the view; INCLUDE adds dimensions to the view and computes at a finer grain; EXCLUDE removes dimensions from the view and computes at a coarser grain. FIXED runs before dimension filters and can return a dimension, while INCLUDE and EXCLUDE run after them and always return measures.

What is the DAX equivalent of a Tableau FIXED LOD expression?

CALCULATE with ALLEXCEPT. {FIXED [Region] : SUM([Sales])} becomes CALCULATE(SUM(Sales[Amount]), ALLEXCEPT(Sales, Sales[Region])). When Region sits on a dimension table rather than the fact table, use REMOVEFILTERS() combined with VALUES(Geography[Region]) so filters arriving through relationships are cleared too.

Does ALLEXCEPT behave exactly like FIXED?

No. ALLEXCEPT only clears filters on columns of the table you pass it, so in a star schema a slicer on another dimension still reduces the result — something the Tableau LOD ignored. It also does not reproduce context filters, which FIXED respects; those map to ALLSELECTED instead.

How do you convert an INCLUDE LOD expression to DAX?

Use an iterator over the included dimension. AVG({INCLUDE [Customer] : SUM([Sales])}) becomes AVERAGEX(VALUES(Customer[CustomerKey]), CALCULATE(SUM(Sales[Amount]))). Match the iterator to the outer aggregate — MAXX for MAX, MINX for MIN. The inner CALCULATE is required: it triggers the context transition.

Does Antares convert LOD expressions automatically?

Yes, on the Tableau to Power BI route, with a manual fallback. Stereotyped shapes such as a bare FIXED total, FIXED over a list of columns, a percent of a FIXED total and a simple EXCLUDE have one safe DAX template and are written deterministically; other LODs go through a guardrailed AI step held to fixed FIXED, INCLUDE and EXCLUDE patterns and validated before the result is kept. An LOD with no safe DAX shape is reported as a manual action with the reason rather than guessed at. Before conversion, the free Analyzer counts every LOD by type, so the work is known before the migration starts.

Let's talk migration.

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