Tableau — dimensions, measures, calculations and Level of Detail
How Tableau thinks about data, and how to compute anything with calculated fields, parameters, sets, groups, table calculations and LOD expressions.
This lesson builds on: Power BI Desktop, Power Query and the star schema.
- Connect to data and explain dimensions vs measures and discrete vs continuous fields
- Build worksheets with the shelves and Marks card
- Write calculated fields, parameters, sets and groups
- Choose correctly between table calculations and LOD expressions (FIXED, INCLUDE, EXCLUDE)
How Tableau thinks
Tableau (Desktop, or the free Tableau Public) builds a query from what you drag onto shelves. Every field is:
- a dimension (categorical — slices the data: Store, Category) or a measure (numeric — aggregated: SUM(Revenue));
- discrete (blue pills — create headers) or continuous (green pills — create axes).
order_date placed as discrete YEAR gives one column per year; as continuous MONTH it gives a time axis. Recognising pill colour explains most "why does my chart look like this" moments.
Data connections
Connect → Text file / Microsoft Excel / server. Use the relationships canvas (the "noodles") to relate orders, order_items, products, stores on their keys. Tableau relationships are context-aware: each table is aggregated at its own level before joining, which avoids the fan-out that physical joins cause. Choose Extract (a fast snapshot, like Import) or Live (like DirectQuery).
Worksheets and the Marks card
A worksheet = one view. Drag category to Rows and SUM(Net Revenue) to Columns → a bar chart. The Marks card controls mark type and encodings (Colour, Size, Label, Detail, Tooltip). Show Me suggests chart types, but choose deliberately using the rules from the Power BI design lesson.
Calculated fields
Analysis → Create Calculated Field:
// Net Revenue (row level)
[quantity] * [unit_price] * (1 - [discount_pct])
// Completed Net Revenue (row level, NULL otherwise)
IF [status] = "completed" THEN [quantity] * [unit_price] * (1 - [discount_pct]) END
// Average order value (aggregate calculation)
SUM([Completed Net Revenue]) / COUNTD([order_id])
Row-level calculations compute per row then aggregate; aggregate calculations (containing SUM, COUNTD…) compute after aggregation — like DAX measures. You cannot mix aggregated and non-aggregated fields in one expression ("cannot mix aggregate and non-aggregate arguments").
Parameters, groups and sets
- Parameter: a user-controlled value (e.g. Top N = 10, or a discount scenario) used in calculations and filters. Show the parameter control on the dashboard.
- Group: combine dimension members (e.g. Baku Central + Baku Riverside + Baku Airport → "Baku stores").
- Set: a subset of members defined by a condition (top 20 customers by revenue) — dynamic, and usable for in/out comparisons ("In set" vs "Out of set").
Filters
Filter order matters: Extract → Data source → Context → Dimension → Measure → Table calculation filters. A "Top 10 products" filter computes on all data unless the category filter is added to context first — a classic gotcha.
Table calculations
Table calculations compute on the results in the view (like window functions over the visual's table): running total, percent of total, difference from previous, rank, moving average.
Right-click SUM(Revenue) → Quick Table Calculation → Percent Difference → Compute Using: Table (across) for month-over-month. "Compute Using" (addressing/partitioning) is the equivalent of SQL's PARTITION BY/ORDER BY — set it explicitly.
Level of Detail (LOD) expressions
LOD expressions compute an aggregate at a level different from the view:
| Expression | Meaning |
|---|---|
{ FIXED [customer_id] : MIN([order_date]) } |
Each customer's first order date, regardless of the view |
{ INCLUDE [order_id] : SUM([Net Revenue]) } |
Compute per order, then aggregate to the view (e.g. AVG order value per store) |
{ EXCLUDE [category] : SUM([Net Revenue]) } |
Total ignoring category — for share-of-total |
FIXED customer first-order date is the foundation of cohort analysis in Tableau. The equivalent SQL — the cohort sizes you would see after placing the FIXED field (as month) on Rows with COUNTD(customer_id):
WITH firsts AS (SELECT customer_id, MIN(order_date) AS first_order FROM orders WHERE status = 'completed' GROUP BY customer_id)
SELECT strftime('%Y-%m', first_order) AS cohort_month, COUNT(*) AS customers
FROM firsts GROUP BY 1 ORDER BY 1 LIMIT 6;| cohort_month | customers |
|---|---|
| 2023-01 | 615 |
| 2023-02 | 324 |
| 2023-03 | 371 |
| 2023-04 | 248 |
| 2023-05 | 198 |
| 2023-06 | 194 |
FIXED LODs are computed before dimension filters (unless those filters are in context). Filtering to "Ganja" does not change a FIXED customer total computed over all stores. Add the filter to context if it should apply.
Concept mapping: Tableau ↔ Power BI
| Tableau | Power BI |
|---|---|
| Measure (aggregate calc) | DAX measure |
| Row-level calculated field | Calculated column / Power Query column |
| Table calculation | Visual calculation / window functions in DAX (WINDOW, OFFSET) |
| FIXED LOD | CALCULATE with ALLEXCEPT / grouped measure |
| EXCLUDE LOD | CALCULATE with REMOVEFILTERS |
| Parameter | What-if parameter / field parameter |
| Extract | Import mode |
Practice
In Tableau, a green pill on a shelf indicates a field that is:
Which expression returns each customer's first order date regardless of the dimensions in the view?
A 'percent difference from previous' table calculation gives strange results. What should you check first?
Summary
- Dimensions slice, measures aggregate; blue = discrete, green = continuous.
- Calculated fields are row-level or aggregate; don't mix them.
- Parameters, groups and sets add interactivity and custom segments; mind filter order and context filters.
- Table calculations work on the view (set Compute Using); LODs compute at a chosen level — FIXED ignores dimension filters unless in context.