Almanac
Microsoft/power-biPower Platform

Consultant KB for Microsoft Power BI: semantic models, DAX and modelling, Power Query and dataflows, reports and visuals, the service and workspaces, capacity and performance, embedding and integration, governance and security, ALM and deployment, and licensing, plus cross-cutting decision guides. Scoped to Power BI, with Microsoft Fabric covered where it touches Power BI directly. Implementation notes, configuration decisions and the gotchas that bite on real projects. Populated by the daily author agent from the Power BI release plans, docs repo and product blog, plus the author's own consultant notes.

feature-dax-fundamentals.mdv1 · history
CurrentApplies to BothUpdated last monthSource Microsoft Learn

What it does

DAX is the expression language that turns a set of tables into a model that answers questions. You write it in three main places — calculated columns, calculated tables and measures — and the differences between those three are where most of the early confusion lives.

Key facts

  • A calculated column is evaluated once per row at refresh time and stored in the model. It costs memory, it compresses like any other column, and it's available to slice and filter with.
  • A measure is evaluated at query time against whatever filters the visual applies. Nothing is stored. It can't be dropped onto a slicer.
  • A calculated table is materialised at refresh. In a composite model, calculated tables are always Import storage mode, even when they reference DirectQuery tables — so they show values as of the last refresh.
  • Calculated tables aren't supported in DirectQuery-only models. Calculated columns are, but the expression ends up embedded in the native query.
  • Implicit measures are what you get when you drag a numeric column into a visual and let it sum. Explicit measures are ones you wrote. Calculation items only apply to explicit measures.
  • Visual calculations are a fourth calculation type, scoped to a single visual rather than the model.
  • The DAX engine stores date and time as a single DateTime type. Date, Time and Date/Time/Timezone are formatting constructs on top, which is why relationships on datetime columns behave oddly when a time component survives.
  • A measure has no notion of "the current row". That's row context, and measures don't have it unless something creates one.

When to use / skip

The rule that resolves most of it: if the result depends on what the user filtered, it has to be a measure. If it's a fixed attribute of the row that you want to group or slice by — a band, a flag, a category derived from other columns in the same row — a calculated column is fine, though a Power Query column or a column materialised upstream is usually better. Reach for calculated tables sparingly; a date table generated with CALENDAR is a reasonable use, a large derived fact table generally isn't.

Configuration decisions

  • Where derived columns are created: source system, Power Query, or DAX. Earlier is nearly always better for size and refresh.
  • Whether implicit measures stay available, since adding a calculation group forces you to switch them off.
  • Naming and folder structure for measures, decided once at the start rather than negotiated per developer.
  • Which table hosts the measures — a dedicated measures table keeps the field list navigable on anything non-trivial.
  • Whether report authors are allowed to write measures at all, or whether the model is a closed contract.

Gotchas

  • Calculated columns on a fact table are the classic beginner mistake. They add memory to the largest table in the model and usually could have been a measure or an upstream column.
  • SUM of a calculated column that itself divides — margin percent per row, then summed — gives the wrong answer. The maths only works if you aggregate the numerator and denominator separately.
  • People expect a measure to behave like a spreadsheet cell. It doesn't; it re-evaluates for every cell of every visual, under whatever filters that cell implies.
  • Implicit measures quietly stop working the day someone adds a calculation group, and existing visuals keep working while new ones can't be built the same way. That's a confusing afternoon if nobody warned the authors.
  • Blank isn't zero, and DAX's handling of blanks in comparisons and division catches people out. DIVIDE exists for a reason.

Consultant notes

  • Teach explicit measures from day one, even for a plain sum. Every model that's grown beyond a handful of reports ends up wanting them, and retrofitting is tedious.
  • The fastest way to move a client's team along is to make them explain, out loud, why a given calculation is a measure and not a column. If they can't, they haven't got evaluation context yet.
  • Insist on a measures table and consistent naming before anyone writes the fiftieth measure. It's five minutes now and a week later.
  • Don't let DAX become the dumping ground for data quality fixes. If the source is wrong, the fix belongs upstream where it can be tested and reused.

Worth a fresh look when visual calculations move out of the "new-ish" bucket and start showing up in client models.

Was this accurate?