Historical Context & Motivation
Before the advent of modern visual analytics platforms, analysts working with SQL-based reporting tools frequently encountered a frustrating limitation: any filter applied to a query would uniformly restrict every aggregation in the result set. If you filtered to show only the year 2023, every sum, average, and count was scoped exclusively to 2023 data — there was no straightforward way to display a 2023-filtered metric alongside a grand-total metric computed across all years. Achieving such mixed-granularity results required subqueries, common table expressions, or window functions that many business users found inaccessible. Tableau set out to democratize analytics, but as its user base grew more sophisticated, the demand for calculations that could transcend or restrict the visible level of detail became impossible to ignore.
The central question that LOD expressions address is deceptively simple: how do you compute a measure at a granularity that differs from what the current view shows, and how do filters interact with that computation? Understanding this interaction is not optional — misusing it produces silently incorrect numbers. The remainder of this lesson dissects Tableau's query pipeline, clarifies the role of context filters, and equips you to combine LOD expressions with filters responsibly.
Core Principles & Definitions
Before diving into the mechanics, it is essential to formalize the vocabulary. A Level of Detail (LOD) expression in Tableau is a calculated field whose aggregation granularity is explicitly declared in the formula itself, rather than being inferred from the dimensions present on the visualization shelves. The three LOD keywords — FIXED, INCLUDE, and EXCLUDE — each establish a different relationship between the formula's grain and the view's grain. Meanwhile, Tableau processes filters in a strict sequence known as the order of operations (or query pipeline), and the position of an LOD expression within that pipeline determines which filters can affect it.
FIXED LOD
{ FIXED [Dim] : AGG(Measure) }. Because FIXED is evaluated early in the pipeline, most dimension filters do NOT affect it unless promoted to context filters.INCLUDE LOD
{ INCLUDE [Dim] : AGG(Measure) }. INCLUDE is affected by dimension filters because it is evaluated at or after the dimension filter stage.EXCLUDE LOD
{ EXCLUDE [Dim] : AGG(Measure) }. Like INCLUDE, it respects dimension filters.Context Filter
Order of Operations (Query Pipeline)
Visual Explanation — Tableau's Order of Operations
The diagram above is the conceptual backbone of every decision you will make when combining LOD expressions with filters. When you drag a dimension to the Filters shelf and set it to show only a subset of values, Tableau by default places that filter at stage 5 — after FIXED LOD computations have already been resolved. This means a { FIXED [Region] : SUM([Sales]) } calculation will sum sales across all categories even if a dimension filter restricts the view to a single category. To make the FIXED expression respect that filter, you must promote the filter to a context filter (stage 3), effectively shrinking the dataset before the FIXED computation fires. INCLUDE and EXCLUDE expressions, in contrast, sit at stage 6, meaning they naturally respect dimension filters without any promotion.
How It Works — LOD Semantics and Filter Interaction
Formal Semantics of LOD Expressions
While Tableau does not expose SQL directly to the user, each LOD expression translates to a subquery or a window function under the hood. Understanding this translation clarifies why filter placement matters. Consider a view with [Category] on Rows and SUM([Sales]) on Columns. Adding a FIXED expression { FIXED [Region] : SUM([Sales]) } effectively generates a correlated subquery that groups by Region and joins the result back to every row in the main query. Because this subquery is logically evaluated before dimension filters, the subquery's WHERE clause includes only extract-level, data-source-level, and context-level filter predicates.
filtered_data represents the dataset after stages 1–5 (including dimension filters). The INCLUDE expression then adds [IncludedDim] to the GROUP BY, producing a finer grain. Because dimension filters have already run, INCLUDE naturally respects them.[ExcludedDim] from the GROUP BY, yielding a coarser grain. Like INCLUDE, it respects dimension filters.Context Filters — Conceptual Model
When you add a dimension filter to context, Tableau conceptually creates a temporary materialized table containing only the rows that pass the context filter predicate. All subsequent stages — including FIXED LOD — operate on this reduced table rather than the full data source. This is analogous to creating a CTE (Common Table Expression) in SQL: WITH ctx AS (SELECT * FROM DataSource WHERE [context_predicate]) and then running every other query against ctx. The performance implication is worth noting: because Tableau materializes this intermediate result, context filters can introduce latency on large datasets, but they guarantee semantic correctness when FIXED expressions must honor certain filter conditions.
Detailed Breakdown — Filter Types and Their Pipeline Position
Tableau supports several filter types, each occupying a specific slot in the query pipeline. Misidentifying which filter type you are using is a common source of incorrect LOD results. The table below provides a comprehensive classification, including each filter's pipeline stage, its interaction with FIXED LOD, and practical use cases.
| Filter Type | Pipeline Stage | Affects FIXED? | Affects INCLUDE/EXCLUDE? |
|---|---|---|---|
| Extract Filter | Stage 1 — earliest | Yes | Yes |
| Data Source Filter | Stage 2 | Yes | Yes |
| Context Filter | Stage 3 | Yes ✓ | Yes |
| Dimension Filter (standard) | Stage 5 | No ✗ | Yes |
| Measure Filter | Stage 7 | No | No |
| Table Calc Filter | Stage 8 — latest | No | No |
The second diagram makes the practical implications concrete. In Scenario A, the FIXED expression calculates total sales per region across all categories because the Category filter has not yet executed when FIXED fires. The view shows only Furniture rows, but the FIXED value of $500K for East includes Technology and Office Supplies as well — a classic gotcha. In Scenario B, promoting Category to a context filter restricts the underlying data to Furniture rows before FIXED executes, yielding the correct $180K. The decision flowchart codifies a simple heuristic: whenever you combine FIXED LOD with a dimension filter and you intend the filter to constrain the FIXED computation, add the filter to context.
Worked Example — Customer Cohort Analysis with Context Filters
Suppose you are analyzing the Superstore dataset. Your goal is to build a bar chart showing the number of customers whose first purchase fell in each year, but only for customers who have purchased items in the Technology category. The first-purchase year is computed via a FIXED LOD expression on [Customer ID].
[First Purchase Year] with the formula: { FIXED [Customer ID] : MIN(YEAR([Order Date])) }. This returns the earliest order year for each customer, regardless of the dimensions in the view.{ FIXED [Customer ID] : MIN(YEAR([Order Date])) }[First Purchase Year] (converted to a discrete dimension) on Columns and COUNTD([Customer ID]) on Rows. At this point, the chart correctly shows how many customers made their first purchase in each year across the entire dataset.[Category] to the Filters shelf and select only 'Technology'. The bar chart now shows only Technology rows, but the FIXED expression was computed before this filter. This means a customer who first purchased a Furniture item in 2018 but also bought Technology in 2020 will appear in the 2018 cohort, since the FIXED value was computed on unfiltered data. Worse, customers who never purchased Technology may still have their FIXED value computed, though they are excluded from COUNTD due to the dimension filter. The cohort counts and years may be subtly wrong.[Category] filter pill on the Filters shelf and select 'Add to Context'. The filter pill changes color (gray background in Tableau's UI) indicating it is now a context filter. Tableau materializes a temporary table of only Technology rows. The FIXED expression is now re-evaluated on this reduced dataset: { FIXED [Customer ID] : MIN(YEAR([Order Date])) } now only considers Technology orders when determining each customer's first-purchase year.Strengths, Limitations, and Common Pitfalls
| Aspect | Strength | Limitation / Pitfall |
|---|---|---|
| FIXED LOD | Computes at an exact grain independent of the view; essential for cohort analysis, benchmarks, and ratios against a fixed denominator. | Ignores standard dimension filters, leading to silently incorrect values unless context filters are used. Can cause confusion when the same calculated field is reused across worksheets with different filter configurations. |
| Context Filters | Provide a clean mechanism to scope FIXED expressions; conceptually simple (shrink the dataset first). | Introduce temporary table materialization, which may degrade performance on live connections. Over-reliance can mask design issues — sometimes restructuring the LOD expression is preferable. |
| INCLUDE/EXCLUDE | Naturally respect dimension filters, reducing the need for context filters. More intuitive for adding or removing granularity relative to the view. | Cannot define an arbitrary grain — they only add to or subtract from the view's dimensions. Not suitable when the desired grain has no relationship to the view. |
| Table Calc Filters | Execute last in the pipeline, so they hide marks without altering underlying computations — useful for top-N filtering without distorting LOD values. | Cannot affect any LOD expression. Often misunderstood by users who expect them to behave like dimension filters. |
Connection to Advanced Theory — Nested LOD, Parameters, and Sets
The interplay between LOD expressions and filters extends into more advanced Tableau patterns. Nested LOD expressions — where one LOD wraps another — follow the same pipeline rules, but the innermost expression is evaluated first, and its result is treated as a row-level value for the outer expression. Set-based filtering introduces another nuance: when a set is placed on the Filters shelf, it behaves as a dimension filter (stage 5), meaning it does not affect FIXED LOD unless the set filter is added to context. Similarly, parameter-driven filters implemented via calculated fields on the Filters shelf follow dimension filter semantics unless explicitly promoted.
| Pattern | Basic Approach (this lesson) | Advanced Extension |
|---|---|---|
| Scoping FIXED | Promote a single dimension filter to context | Use nested FIXED with an inner expression that pre-filters via a Boolean condition, avoiding context filters entirely |
| Dynamic granularity | Choose INCLUDE or EXCLUDE based on static needs | Use parameters to swap dimension references inside LOD expressions dynamically |
| Top-N within groups | Table calc filter to hide marks | Combine FIXED with RANK table calc, then use set actions for interactive top-N that respects LOD |
| Cross-database LOD | Single data source LOD | LOD across blended data sources (limited — FIXED only works within primary source) |
As you progress into Tableau Prep, Tableau Server (now Tableau Cloud), and embedded analytics, the LOD-filter interaction remains unchanged — the query pipeline is a constant across all Tableau products. Building a solid mental model of this pipeline now will pay dividends when you encounter row-level security filters (which operate at the data source level, stage 2) or initial SQL (which runs before even extract filters). Each mechanism is simply another station on the same assembly line.
Practice Problems
{ FIXED [Customer ID] : SUM([Sales]) } expression is not affected when you filter the view to show only the 'West' region using a standard dimension filter. Reference the query pipeline stages in your answer.{ FIXED [Region] : AVG([Profit]) }. Your view has [Category] on Rows and the FIXED field on Columns, with a standard dimension filter on [Segment] = 'Consumer'. What value does the FIXED field show — the average profit per region for Consumer only, or for all segments? What single change makes it respect the Segment filter?{ FIXED [Customer ID] : SUM([Sales]) }. The Region filter should scope both charts. Describe your filter design, including whether you use context filters, dashboard filter actions, or another approach, and justify your choice from a performance and correctness standpoint.{ FIXED : COUNTD([Customer ID]) } (a FIXED expression with no dimension specified). This computes the grand total of distinct customers. Now suppose you have a standard dimension filter on [Category] = 'Furniture' and a context filter on [Region] = 'East'. What value does this expression return? Generalize your answer: describe the rule governing a FIXED expression with an empty dimension list and its interaction with each filter type.Summary
Tableau's LOD expressions — FIXED, INCLUDE, and EXCLUDE — allow you to compute measures at granularities that differ from the visualization's level of detail. The critical insight is that these expressions occupy specific positions within Tableau's order of operations (query pipeline): FIXED is computed at stage 4, before standard dimension filters (stage 5), while INCLUDE and EXCLUDE are computed at stage 6, after dimension filters. This ordering means FIXED expressions are immune to dimension filters by default.
To make a dimension filter constrain a FIXED expression, promote it to a context filter (stage 3), which materializes a temporary table before FIXED fires. Use context filters deliberately: they ensure correctness but may incur a performance cost on live connections. Always audit FIXED expressions whenever new filters are added to a workbook, and prefer INCLUDE or EXCLUDE when the desired granularity can be expressed as an addition to or subtraction from the view's dimensions, since these types naturally respect dimension filters without requiring context promotion.