Tableau Migration LOD DAX Power BI

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

July 27, 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.

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

Antares does not auto-translate LOD expressions, and that is deliberate: a silently wrong rewrite costs far more to find in UAT than a flagged one costs to write by hand. What the Analyzer does instead is find them. Every calculated field in the workbook is parsed and classified, and each LOD lands in the migration report as an explicit manual action with its type and the recommended DAX approach, rather than as a formula somebody discovers late.

That inventory is also what makes an estimate defensible — 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 Complete Migration Guide

Related Migration Resources

Frequently asked questions

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?

No, by design — a silently wrong rewrite costs more to find in UAT than a flagged one costs to write by hand. The Analyzer parses every calculated field, identifies each LOD and its type, and reports it as a manual action with the recommended DAX approach, 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.