Everything you need to understand and apply Tableau Level of Detail expressions — the conceptual model that makes LODs click, FIXED for pre-aggregation at a specified grain, INCLUDE for adding detail below the view, EXCLUDE for removing dimensions, and the performance implications of each approach.
Level of Detail (LOD) expressions are the most powerful calculation type in Tableau. They are also the most commonly misunderstood. Most Tableau users understand table calculations (computed after data is returned from the query) and aggregate expressions (SUM, AVG, COUNT). LOD expressions sit between these — they are aggregate calculations that operate at a specified grain, independent of the current view's level of detail.
Once the conceptual model clicks, LOD expressions become the answer to a wide range of problems that would otherwise require complex table calculations, multiple data sources, or data preparation outside Tableau.
The Conceptual Model
In a Tableau view, there is an implicit grain — the level of detail determined by the dimensions in the view. A bar chart showing Revenue by Region has a grain of Region: one row per region, with Revenue summed across all records in each region.
An LOD expression lets you specify an explicit grain for a calculation, independent of the view grain. This is the entire purpose of LOD expressions: compute an aggregate at a grain that is different from the current view grain.
The three LOD types specify how the explicit grain relates to the view grain:
**FIXED:** Compute the aggregate at the specified grain, ignoring the view's dimensions. The result is the same for every mark in the view that shares the same fixed dimension value, regardless of what other dimensions are in the view.
**INCLUDE:** Compute the aggregate at the specified grain — which includes the view's dimensions plus additional dimensions you specify. INCLUDE makes the grain finer than the view grain.
**EXCLUDE:** Compute the aggregate at the view's grain with the specified dimensions removed. EXCLUDE makes the grain coarser than the view grain.
FIXED LOD Expressions
FIXED is the most widely used LOD type. It specifies an explicit grain for a calculation that overrides the view grain — the calculation always aggregates at the fixed grain, regardless of how many other dimensions are added or removed from the view.
Syntax:
{ FIXED [Dimension1], [Dimension2] : AGGREGATE([Measure]) }
Example: Customer-level revenue in a product-level view.
A view showing Revenue by Product requires computing each product's percentage of each customer's total spend. The denominator — total spend per customer — must be computed at the customer grain regardless of the product-level view grain.
{ FIXED [Customer ID] : SUM([Revenue]) }
This FIXED LOD computes the total revenue per customer, regardless of any other dimensions in the view. In a view grouped by Product, each product row can show:
SUM([Revenue]) / [Customer Total Revenue]
Where Customer Total Revenue is the FIXED LOD above. Each product row correctly shows its percentage of the customer's total — the FIXED LOD holds the customer-level total constant while the view grain shows product-level detail.
Example: Customer's first order date.
{ FIXED [Customer ID] : MIN([Order Date]) }
This always returns the earliest order date per customer, regardless of what dimensions are in the view. Useful for cohort analysis: even in a product-level view, you can colour marks by the customer's first order month.
Example: Pre-aggregated totals for percentage calculations.
A classic LOD use case: "Revenue as a percentage of total revenue across all categories." The denominator is the grand total — the sum across all categories:
{ FIXED : SUM([Revenue]) }
An empty FIXED (no dimensions specified) aggregates across the entire table, ignoring all view dimensions. This is equivalent to a grand total.
INCLUDE LOD Expressions
INCLUDE adds dimensions to the calculation grain that are not in the view. This makes the calculation operate at a finer grain than the view.
**When to use INCLUDE:** When you need an average or aggregate "per sub-item" where the sub-item is not in the view, but you want the result at the view's grain.
Example: Average order lines per order in an order-level view.
A view shows Revenue per Order. You want to show "average number of line items in this order" — but line items are not in the view (showing them would change the grain to order-line level).
{ INCLUDE [Order Line ID] : COUNTD([Order Line ID]) }
This INCLUDE LOD counts distinct order line IDs at the grain of the view (order) plus the included dimension (order line ID). It computes the count of order lines per order, then when aggregated in the view (e.g., AVG), gives the average order lines across orders.
Example: Average revenue per customer per region in a region-level view.
A view shows Revenue by Region. You want "average revenue per customer in this region" — but customer is not in the view.
AVG( { INCLUDE [Customer ID] : SUM([Revenue]) } )
The INCLUDE LOD computes total revenue per Customer per Region (the implicit grain of the INCLUDE is the view grain Region plus the included dimension Customer ID). Wrapping it in AVG gives the average customer revenue within each region.
EXCLUDE LOD Expressions
EXCLUDE removes dimensions from the calculation grain that are in the view. This makes the calculation operate at a coarser grain than the view.
**When to use EXCLUDE:** When you need a subtotal at a higher level than the current view, displayed as context alongside the fine-grained view.
Example: Regional subtotal in a product-level view.
A view shows Revenue by Region and Product. You want to show the Regional total (removing the Product dimension) alongside each product row — for comparison context.
{ EXCLUDE [Product] : SUM([Revenue]) }
This EXCLUDE LOD computes Revenue at the Region grain (by excluding Product from the view grain of Region + Product). Each product row shows the same regional total, allowing percentage-of-region calculations.
Example: Week total in a day-level view.
A view shows daily revenue. You want to show the weekly total for each day's row.
{ EXCLUDE [Day] : SUM([Revenue]) }
Assuming the view grain is Week + Day, excluding Day gives a weekly total that appears on every day row within the week.
Performance Implications
LOD expressions are computed at query time (not after data is returned, like table calculations). FIXED LOD expressions generate a query at the fixed grain and then join the results back to the view. This is generally fast — a single pre-aggregation pass rather than row-by-row computation.
However, LOD expressions interact with context filters. FIXED LOD expressions are computed after dimension filters but before context filters are applied. If your FIXED LOD should be filtered by a view-level filter, you must either add that filter to the FIXED LOD itself, or convert the filter to a context filter.
FIXED vs table calculation performance:
For a running total calculation (cumulative revenue from the start of the year), a FIXED LOD that pre-computes the cumulative sum is faster than a WINDOW_SUM table calculation on large datasets — the FIXED LOD is pre-aggregated once; the table calculation is computed for every mark on every render.
FIXED vs data-source-level aggregation:
If a FIXED LOD calculation is expensive and used frequently, consider whether the calculation should be pre-computed in dbt or a SQL view rather than computed in Tableau. A customer's first order date computed as a FIXED LOD on millions of orders is computed every time the view renders. The same calculation computed as a column in a dbt model is computed once during the dbt run.
Common LOD Patterns
Cohort assignment:
{ FIXED [Customer ID] : MIN(DATETRUNC('month', [Order Date])) }
Assigns each customer to their acquisition cohort (the month of their first order). Used in every cohort retention analysis.
Prevalence (% of customers who did X):
COUNTD( IF [Condition] THEN [Customer ID] END ) /
{ FIXED : COUNTD([Customer ID]) }
The denominator is the total distinct customers across the entire dataset (empty FIXED = grand total).
Count-then-average (average order lines per order):
AVG( { INCLUDE [Order ID] : COUNTD([Order Line ID]) } )
YTD total at category level in a sub-category view:
{ FIXED [Category] : SUM(IF YEAR([Order Date]) = YEAR(TODAY()) THEN [Revenue] END) }
Our Tableau consulting practice builds advanced analytical workbooks using LOD expressions and other advanced calculation types — contact us if you need support with complex Tableau development.
A former Microsoft data architect audits your data foundation, identifies your top priorities, and sends you a written plan. Free. No pitch.
Book a Call →