Tableau LOD Expressions: FIXED, INCLUDE, EXCLUDE, and Order of Operations

There's a moment every Tableau user hits where the tool seems to actively fight them. You want "average customer order value" but the average keeps changing as you add dimensions to the view. You want each customer's total to sit next to a single row, but Tableau insists on aggregating to whatever's on the shelves. You fight the granularity of the visualization, and you lose — until you learn the one feature that lets you compute at a granularity different from the view. That's Level of Detail (LOD) expressions, and they're the dividing line between people who use Tableau and people who command it.

The core idea in one sentence: an LOD expression computes an aggregate at a level of detail you specify, independent of the dimensions in the view. Normally Tableau aggregates at the view's granularity (whatever's on Rows, Columns, etc.). LOD expressions let you say "no, compute this per customer" — or per region, or across everything — regardless of what the visualization is showing. Three keywords do it: FIXED, INCLUDE, EXCLUDE.

The mental model: view granularity vs. computation granularity

Every Tableau viz has a level of detail — the combination of dimensions that defines a mark. A bar chart of sales by region has a granularity of "region"; one mark per region. By default, every aggregate (SUM(Sales)) is computed at exactly that granularity. The trouble starts when the number you need isn't at the view's granularity. "Total sales per customer" is at customer granularity, but your view might be at region granularity, or month, or have no dimensions at all. LOD expressions decouple the two: the view stays at its granularity, while the expression computes at the one you declare.

graph TD
    DATA[("Row-level data")]
    subgraph DEFAULT["Default aggregation"]
        VG["View granularity
(dimensions on shelves)"] AGG["SUM/AVG computed
AT the view granularity"] VG --> AGG end subgraph LOD["LOD expression"] DECL["You declare a granularity
FIXED / INCLUDE / EXCLUDE"] COMP["Aggregate computed
at THAT granularity,
independent of the view"] DECL --> COMP end DATA --> DEFAULT DATA --> LOD

The distinction that makes LODs click. Normally Tableau computes aggregates at the view's granularity — change the dimensions on the shelves and every number recomputes. An LOD expression breaks that coupling: you declare the granularity in the calculation itself, and the result is computed at that level no matter what the view shows. FIXED ignores the view entirely; INCLUDE and EXCLUDE adjust relative to it.

The three keywords

FIXED — compute at exactly this granularity, ignore the view

FIXED is the one you'll use most and the easiest to reason about: it computes the aggregate at the dimensions you list, completely ignoring what's in the view. { FIXED [Customer] : SUM([Sales]) } gives total sales per customer, full stop — whether your view is showing regions, months, or nothing. Because it's view-independent, the same customer total appears wherever that customer's rows are, which is exactly what you want for things like "customer lifetime value next to every order."

// Total sales per customer — same value regardless of what's in the view
{ FIXED [Customer ID] : SUM([Sales]) }

// Customer's first purchase date — a per-customer scalar
{ FIXED [Customer ID] : MIN([Order Date]) }

// Grand total across everything (no dimension) — useful for % of total
{ FIXED : SUM([Sales]) }

INCLUDE — the view's dimensions, plus more

INCLUDE computes at the view's granularity plus the dimensions you add, then aggregates back up to the view. The classic use: "average sales per customer, shown by region." You want to compute at customer level (finer than region) but display by region. AVG({ INCLUDE [Customer] : SUM([Sales]) }) computes each customer's total, then averages those per-customer totals up to region. INCLUDE shines when you need a finer granularity than the view for the inner calc, then roll it up.

EXCLUDE — the view's dimensions, minus some

EXCLUDE goes the other way: compute at the view's granularity minus the dimensions you remove. The textbook case is "percent of total" where you want the denominator to ignore one dimension. If your view is sales by region by month, { EXCLUDE [Month] : SUM([Sales]) } gives the per-region total across all months, which you can divide into the monthly value to get each month's share of its region. EXCLUDE is how you compute a coarser benchmark to compare each finer mark against.

KeywordGranularity computed atClassic use
FIXEDExactly the listed dimensions; ignores the viewPer-customer totals, cohorts, grand totals, dedup
INCLUDEView dimensions + listed ones, rolled upAverage of a per-finer-entity aggregate (avg per customer by region)
EXCLUDEView dimensions − listed onesPercent of total, comparing a mark to a coarser benchmark

Order of operations: the part that bites everyone

Here's the thing that turns LODs from "neat" to "why is my filter being ignored?" Tableau executes a viz in a specific order of operations, and where each LOD type sits in that pipeline relative to filters is the source of nearly every LOD surprise.

graph TD
    EF["Extract filters"]
    DS["Data source filters"]
    CF["Context filters"]
    FIX["FIXED LODs computed here"]
    DF["Dimension filters
(normal filter shelf)"] INCEX["INCLUDE / EXCLUDE LODs computed here"] MF["Measure filters"] TC["Table calcs & totals"] EF --> DS --> CF --> FIX --> DF --> INCEX --> MF --> TC

Tableau's order of operations (simplified). The critical fact: FIXED is computed before dimension filters, so a normal filter on the shelf does NOT change a FIXED result — the FIXED value was already calculated. Context filters sit above FIXED, so they DO affect it. INCLUDE/EXCLUDE are computed after dimension filters, so they respect them. Knowing exactly where your LOD sits explains every "my filter isn't working" moment.

FIXED ignores your dimension filters — this is the #1 LOD confusion, and it's a feature, not a bug. Because FIXED is computed before the dimension filters on the shelf, filtering the view to one region does not shrink a { FIXED [Customer] : SUM([Sales]) } — it still reflects all regions, because it was computed before the filter ran. People stare at this for an hour. The fix when you want the filter to apply: promote that filter to a context filter (right-click → Add to Context), which moves it above FIXED in the order of operations so the FIXED calc respects it. If you don't want filtering to affect it (e.g. a true grand total for percent-of-total), leave it as a normal filter — that's the whole point. Either way, decide deliberately; don't discover it by accident in front of a stakeholder.

LOD vs. table calculations: which tool

The other recurring question is when to use an LOD versus a table calculation. They overlap, but the distinction is clean once you see it: LOD expressions are computed in the database query, at a declared granularity, before the results come back; table calculations run after, on the aggregated result table that's already in the view, operating on the layout of marks (running totals, rank, percent difference from the previous mark). If your problem is "compute at a different granularity than the view," that's LOD. If it's "do arithmetic across the marks already in the view" (compare this month to last, rank within a partition), that's a table calc. Reaching for a table calc to fake a different granularity — or an LOD to fake a running total — is how people tie themselves in knots.

The decision heuristic I give every analyst: does the answer depend on a granularity not in the view, or on the arrangement of marks in the view? "Each customer's total, shown anywhere" → granularity not in the view → LOD (FIXED). "This region's share of the all-region total" → a coarser granularity → LOD (EXCLUDE). "Running total down the months" or "rank of each bar" → depends on the marks' arrangement → table calculation. Get that one fork right and you'll pick the correct tool the first time instead of fighting the wrong one. And prefer FIXED when you can — it's the most predictable and the easiest for the next person to read.

What to carry away

LOD expressions exist to break the default coupling between the view's granularity and the granularity at which you compute. FIXED computes at exactly the dimensions you name, ignoring the view (and, importantly, ignoring normal dimension filters — promote them to context filters when you need them to apply). INCLUDE computes at the view's granularity plus extra dimensions then rolls up; EXCLUDE computes at the view's granularity minus dimensions, for benchmarks and percent-of-total.

The two things that turn LOD frustration into fluency: internalize the order of operations (especially that FIXED runs before dimension filters), and keep the LOD-vs-table-calc fork straight — LODs are about granularity computed in the query; table calculations are about arrangement of marks computed after. Once those click, the moments where Tableau seemed to fight you become the moments you reach for the right keyword and the number simply appears. For how these calculations execute under the hood, see Tableau internals; for the broader performance picture, Tableau best practices.