LowCodeStacks™
Sign in

Calculated column vs measure in Power BI: which to use

Calculated column or measure? Learn where each is worked out, what each costs, when to use which, and why a margin % belongs in a measure, not a column.

Power BIFix a problem9 min read

Checked against Microsoft Learn · 12 sourcesPosted by the Maker DeskHow we write guides

Both are written in DAX and both end up in the Data pane, so the choice between a calculated column vs measure looks like a matter of taste. It isn't. They're worked out at different times, in different contexts, and they cost different things. Pick the wrong one and you get a bigger model, totals that don't add up, or a number that ignores the slicer.

A calculated column worked out at refresh gives order A (100 sales, 50 cost) a line margin of 50% and order B (1,000 sales, 900 cost) 10%; summed they show 60%, averaged 30%, neither right. A measure, DIVIDE of total sales minus total cost by total sales, gives 150 on 1,100: 13.6%. Use columns for slicers, filters, rows and axes, measures for values in visuals, and prefer a Power Query custom column to a DAX column.
The same margin as a column and as a measure: only the measure gets the total right.

The difference in one table

Calculated columnMeasure
Worked outAt data refreshOn demand, when a visual needs it
ResultsSaved in the modelCalculated as required, never stored
ContextRow: the current rowFilter: whatever the slicers, filters, rows and columns select
Changes when someone clicks a slicerNoYes
Where you use itSlicers, filters, rows, columns, axes, legendsValues in a visual, and visual-level filters

Row context means "the current row". A calculated column such as = [Freight] + [Tax] gets the values from the same row, one row at a time, and can follow relationships to related tables with RELATED.

Filter context is the set of rows a visual's cell is looking at. Each cell, each combination of row and column headers, and each slicer selection gives a measure a different subset of data, so the same formula can return a different answer in every cell.

When each one is worked out
  1. Data refresh
  2. Calculated columns are worked out row by row and stored
  3. Someone opens the report or clicks a slicer
  4. Each visual asks for its numbers
  5. Measures are worked out for every cell in that filter context

The storage line is for Import models. In DirectQuery, Microsoft says calculated columns aren't stored and are worked out at query time instead.

When to use a calculated column

Use a column when you need a value per row that people will slice, filter or group by. A measure can't go on a slicer or on a visual's rows or axis.

A price band to slice sales by is a typical example. Right-click the Sales table in the Data pane, choose New column, and enter:

dax
Price band =
SWITCH (
    TRUE (),
    Sales[Amount] < 100, "Under 100",
    Sales[Amount] < 500, "100 to 499",
    "500 and over"
)

Every row gets its band at refresh, and Price band works in a slicer like any other column.

Power Query is often the better place

A custom column in Power Query does the same job before the data enters the model. Microsoft's guidance for Import models prefers it: calculated columns usually compress less well, and they're only built once all the Power Query tables have loaded, which can lengthen the refresh. When the source is a database, Microsoft goes one step further and suggests doing the calculation in the SQL query, or storing it as a column in the source.

In Power Query Editor, select Add column > Custom column and enter:

powerquery
if [Amount] < 100 then "Under 100"
else if [Amount] < 500 then "100 to 499"
else "500 and over"

In Power BI Desktop the Custom column dialog doesn't offer a data type, so set the new column's type afterwards.

Keep the column in DAX when its formula needs a measure, a related table, or a DAX-only function. A customer segment is a good example:

dax
Customer segment = IF ( [Sales Amount] < 2500, "Low", "High" )

Added to the Customer table, this works out each customer's own sales: when you use a measure in a row context, DAX turns the current row into a filter for you (Microsoft calls this context transition). Remember the result is fixed at refresh. Slicing by year won't move a customer from Low to High.

When to use a measure

Use a measure for anything you add up, count, average, divide or compare over time: totals, ratios, percentages, year to date. Select Home > New measure (in the Calculations group) and the result recalculates for every cell, every slicer and every total.

Worked example: margin %

Say the Sales table has an Amount and a Cost for each order line. Here are two lines:

LineAmountCostMargin on the line
A1005050%
B1,00090010%
Real total1,10095013.6%

A Line margin % column gives each line its own margin. Summed in a visual, it shows 60%; averaged, 30%. Neither is the margin of the business, which is 150 profit on 1,100 sales: 13.6%.

The fix is to add up first and divide last, in measures:

dax
Sales Amount = SUM ( Sales[Amount] )

Total Cost = SUM ( Sales[Cost] )

Margin % = DIVIDE ( [Sales Amount] - [Total Cost], [Sales Amount] )

Format Margin % as a percentage. Now each row of a visual, and the total, divides its own sums, so the total shows 13.6%. DIVIDE returns a blank instead of an error when the denominator is zero or blank, and Microsoft recommends it whenever the denominator could be either. Leave out the third argument: a blank lets visuals hide groups with no sales.

Implicit or explicit measures

Drag a numeric column into a visual and Power BI sums it for you. That's an implicit measure, shown with a sigma (∑) in the Data pane. A measure you write yourself is explicit, shown with a calculator icon.

Implicit measures are handy, but Microsoft gives reasons to write explicit ones even for a plain sum:

  • Analyze in Excel uses PivotTables, which send MDX queries, and MDX needs explicit measures.
  • Paginated reports built with the MDX query designer need them too.
  • You control how a column is summarised. A unit price should never be summed, so hide the column and offer measures such as an average, minimum and maximum instead.

Explicit measures can also be reused inside other measures, as Margin % reuses Sales Amount above.

The quick decision

You want to...UseWhy
Put it on a slicer, a filter, rows, columns or an axisColumn (Power Query first, DAX if needed)Measures can't go there
Label or group each row (band, segment, full name)ColumnIt's a fixed value per row
Show a total, count or averageMeasureIt follows every filter
Show a ratio or percentageMeasure with DIVIDEDivide the totals, not the rows
Compare over time (year to date, last year)MeasureThe answer depends on the dates selected
Use a measure's result to group rowsDAX calculated columnMicrosoft's exception to preferring Power Query

Do

  • Add columns as far back as you can: in the source, then Power Query, then DAX.
  • Write explicit measures for anything people will total, and hide the raw columns behind them where summing would be wrong.
  • Build ratios from other measures, so there's one definition of Sales Amount.

Don't

  • Don't store a ratio in a column and let the visual sum or average it.
  • Don't add a column just to feed one number in one visual. A measure's results aren't stored.
  • Don't expect a calculated column to react to a slicer: it was worked out at refresh.

Common mistakes

Picked the wrong one?

  • The percentage total is far too high, or is an average of the rows: it's a column being summed. Rebuild it as a measure.
  • A column made with SUM shows the same grand total on every row: with no filter on the table, SUM ( Sales[Amount] ) adds up the whole column. Make it a measure instead.
  • A column that uses a measure gives one fixed value per row and ignores the slicers: it was worked out at refresh. If it must react to slicers, it has to be a measure.
  • You can't drag a measure onto a slicer: slicers need a calculated column or a real column.
  • A PivotTable in Analyze in Excel can't summarise a column: it sends MDX, which needs explicit measures.

For why totals behave the way they do, see why are my totals wrong. For where the columns should live in the first place, building a star schema from messy exports does most of the work in Power Query, and a date table in Power BI shows the measures that compare periods.

Related: Power BI DAX cheat sheet, Power Query vs Power Pivot vs Power BI.

Sources

Did this fix it?

Comments

No comments yet. Share what worked for you.

Sign in to comment. Comments show under a display name you choose, never your email.