2.3 · Calculated columns vs measures

Level 2 · Model & DAX

2.3Calculated columns vs measures

Goal: Distinguish calculated column and measure, and install the reflex: measure first, column if you need row by row.
Estimated time: 15 min · self-paced reading · If you only have 5 min: read “The essentials in 30s” + the diagram.

The essentials in 30 seconds

  • The measure calculates an aggregate on the fly according to the visual's context (nothing is stored): it is the heart of Power BI.
  • The calculated column adds a value to each row, calculated at refresh and stored: it makes the model bigger.
  • Reflex: measure first; the calculated column is reserved for row-by-row needs (filter, categorise, link) — what must react to filters is a measure.

Running mini-case — Zineb decides storage or on-the-fly

Zineb, a management controller in an agri-food SME in Algiers, wants a margin per sales line and a total that recalculates by city. She thinks she has to put everything in a calculated column. She applies the section: the margin per line = Sales[Amount] * 0.3 is a calculated column (stored value, row by row), whereas Total Revenue = SUM(Sales[Amount]) is a measure (on the fly). She sets up a matrix City × [Total Revenue]: the measure recalculates by city, by total, whereas a column would stay frozen. She remembers the decisive test: what must react to slicers is a measure. Reflex installed: measure first, column if you need row by row.

Standalone case for this section: it returns in the course, the diagram, the script and the 48h challenge of section 2.3.

1. Two ways to calculate

The calculated column adds a value to EACH ROW of the table, calculated at refresh and stored in memory — for example Margin = Sales[Amount] * 0.3. The measure calculates an aggregate ON THE FLY according to the visual's context and stores nothing — for example Total Revenue = SUM(Sales[Amount]). Zineb quickly understands which of the two she is looking at.

2. The decision tree

A calculated column lives in a row context ("the current row"); a measure lives in a filter context ("what the visual filters" — the city of the bar, the month of the column). The decisive test: what must react to the report's filters is a measure. A column that you only ever sum should have been a measure. Zineb asks herself the question for every calculation.

3. Organising your measures

Good habit from now on: group the measures in a dedicated "_Measures" table for a clean model. We keep calculated columns rare, because they make the file bigger. Zineb organises her measures and limits columns to the strict row-by-row needs.

Common misinterpretation: "I do everything with calculated columns, a column reacts to slicers like a measure, and I drag columns into values without thinking". No, triple mistake. What must react to the report's filters is a measure, not a column: a calculated column is frozen at refresh. Reflex: measure first — a column you only ever sum should have been a measure. And implicit measures (dragging a column) get you started but quickly need to be replaced by real explicit measures.
Column vs measure The measure recalculates according to the context; the column stays frozen row by row. Calculated columnStored row by row (filter, link)+MeasureCalculated on the fly according to the context (aggregate)+TestReacts to filters? → measure Store the measures in a dedicated "_Measures" table.
The measure recalculates according to the context; the column stays frozen row by row.
Text version of the diagram (SEO / screen readers / translation): 1) Zineb, a management controller in Algiers, distinguishes the two ways to calculate: the calculated column adds a stored value to each row (Margin = Sales[Amount] * 0.3), the measure calculates on the fly according to the visual's context (Total Revenue = SUM(Sales[Amount])). 2) She applies the decision tree: row context for the column, filter context for the measure — and the decisive test, what must react to filters is a measure. 3) She installs the measure-first reflex, reserves the column for row-by-row needs (filter, link) and stores her measures in a dedicated "_Measures" table. Lesson: a column you only ever sum should have been a measure.

🔎 Concrete example — 🔎 Concrete example — The column vs measure duel

Zineb creates both and compares:

Calculated column: Margin = Sales[Amount] * 0.3   (one value per row)
Measure          : Total Revenue = SUM(Sales[Amount])  (lives in the visuals)
→ matrix City × [Total Revenue]: the measure recalculates by city, by total.

Reading: the measure is recalculated in each cell of the visual (by city, by total).

Lesson: the column shows a frozen value; the measure adapts to the context.

Section vocabulary

Calculated column
New DAX column evaluated row by row and STORED: Margin = Sales[Amount] - Sales[Cost].

Simple example: Zineb calculates a margin per sales line.

What it is not: an aggregate that recalculates according to the visual.

Reflex: row-by-row need (filter, link) → column.

Measure
DAX calculation evaluated on demand in the visual's context: Total Revenue = SUM(Sales[Amount]).

Simple example: Zineb puts [Total Revenue] in a matrix City × Month.

What it is not: a stored value frozen at refresh.

Reflex: what must react to filters → measure.

Row context
The environment of a calculated column: "the current row".

Simple example: Zineb reads the margin of each sale, row by row.

What it is not: the dynamic filtering of a visual.

Reflex: calculated column → think "current row".

Filter context
The environment of a measure: "what the visual filters" (the city of the bar, the month of the column).

Simple example: Zineb recalculates [Total Revenue] by city automatically.

What it is not: a frozen value, identical everywhere.

Reflex: measure → think "what the visual filters".

Implicit measure
The automatic aggregation of a column dragged into values: handy at first, to be replaced by real explicit measures.

Simple example: Zineb replaces her automatic aggregations with [Total Revenue].

What it is not: an explicit measure, named and formatted.

Reflex: as soon as you go beyond the sum, create an explicit measure.

In practice — In practice — The column vs measure duel

  1. Calculated column: Table view, Sales table → New column → Margin = Sales[Amount] * 0.3 — observe the value on each row, like Zineb.
  2. Measure: New measure → Total Revenue = SUM(Sales[Amount]) — nothing shows in the table: it lives in the visuals.
  3. Create a matrix City × [Total Revenue]: the measure recalculates by city, by total — the context in action.
  4. Create the measure Average basket = AVERAGE(Sales[Amount]) and compare it with the average of the Margin column: the storage vs on-the-fly difference.
Both tools in hand and the reflex installed: measure first, column if you need row by row.

Step-by-step script — decide like Zineb (6 min)

1) Create a calculated column: Margin = Sales[Amount] * 0.3, and watch the value appear on each row. 2) Create a measure: Total Revenue = SUM(Sales[Amount]) — it does not show in the table. 3) Put [Total Revenue] in a matrix City × [Total Revenue]: it recalculates by city. 4) Add Average basket = AVERAGE(Sales[Amount]) and compare. 5) Store your measures in a dedicated "_Measures" table, like Zineb.

If a calculation must react to slicers, do not take a column: create a measure.

Copy-paste template — measure or column?

What must REACT to filters (slicers, clicks) → MEASURE (on the fly)
Need for a value ROW BY ROW (filter, categorise, link) → COLUMN
Column: Margin = Sales[Amount] * 0.3
Measure: Total Revenue = SUM(Sales[Amount])
Rule: measure first; store the measures in a "_Measures" table.

Margin per row

Zineb calculates Margin = Sales[Amount] * 0.3 in a column: the value exists on each row (useful for filtering).

Total that reacts

Zineb puts [Total Revenue] as a measure: the total recalculates by city, by month, according to the slicers.

Average basket

Average basket = AVERAGE(Sales[Amount]): a measure that adapts to the visual's context.

Table _Measures

Zineb groups all her measures in a dedicated "_Measures" table: the model stays clean.

✓ Best practices

  • Measure first: it reacts to filters and stores nothing.
  • Calculated column only for a row-by-row need (filter, link).
  • Store the measures in a dedicated "_Measures" table.

✗ Common pitfalls

  • Creating a calculated column that you only ever sum.
  • Multiplying calculated columns (they make the model bigger).
  • Expecting a column to react to slicers (it is frozen).

Key takeaways

  • Measure = calculation on the fly according to the visual's context: the heart of Power BI.
  • Calculated column = value stored row by row: for filtering, categorising, linking — not for aggregating.
  • Reflex: measure first. A column you only ever sum should have been a measure.
  • Organise your measures: a dedicated "_Measures" table groups them cleanly.

48h challenge — apply it tomorrow

Replay Zineb's duel: create a calculated column (Margin = Sales[Amount] * 0.3) and a measure (Total Revenue = SUM(Sales[Amount])), put the measure in a matrix and verify that it recalculates by city. Write in one sentence why what reacts to filters is a measure.

Section exit checklist
  • I distinguish a calculated column from a measure.
  • I choose measure first and column if I need row by row.
  • I organise my measures and explain the context (row vs filter).
Self-assessment 1-5: can I choose between column and measure without hesitating?Self-assessment 1-5: did I prove that a measure recalculates according to the visual?

Frequently asked questions

Why does my calculated column not react to slicers?

By nature: a calculated column is evaluated at refresh, row by row, and its value is stored once and for all. It is therefore frozen and does not see the report's filters. What must react to slicers must be a measure, because a measure is recalculated on the fly in the visual's context.

Are implicit measures (dragging a column) enough?

To start, yes: dragging a numeric column creates an automatic aggregation. But explicit measures quickly become essential: reusable, formattable, documentable, and mandatory for any non-trivial calculation (ratios, time intelligence) and for the PL-300. Store them in a "_Measures" table.

Check your understanding

What must react to the report's filters (slicers, clicks)?

Additional resources (optional, to go further)

Level 2 examFresh, harder questions to test what you've learned