Gyromitra Inc.
← Back to Blog

Study Guide

DAX CALCULATE Explained: 3 Worked Examples for PL-300

By Dr. Rosario Feghali · July 21, 2026 · 9 min read

If there is one DAX function that decides whether you pass PL-300, it's CALCULATE. I have taught this material to well over a thousand candidates, and the pattern is always the same: people can write SUM and AVERAGE on day one, but CALCULATE is where the course slows down. Once it clicks, everything else in DAX — time intelligence, percent-of-total, security filters — starts to make sense, because they're all just CALCULATE underneath.

This post walks through three real examples, from simple to genuinely tricky, with the mechanics explained at each step.

What CALCULATE actually does

CALCULATE takes an expression and evaluates it inside a modified filter context. That's the whole function, in one sentence — but the word "modified" is doing a lot of work, so let's unpack it.

CALCULATE(<expression>, <filter1>, <filter2>, ...)

Every visual, slicer, and row in a Power BI report already applies filters before your measure runs — that's the existing filter context. CALCULATE lets you add to it, override parts of it, or strip it away entirely, and then evaluates <expression> against the result. The filter arguments can be:

  • Boolean filter expressions on a single column, like Sales[Category] = "Bikes"
  • Table expressions, usually built with FILTER, ALL, ALLEXCEPT, or ALLSELECTED

A boolean filter argument replaces any existing filter on that column. It does not add to it. This trips up beginners constantly: if a report page is already filtered to "Bikes" by a slicer, and your measure says CALCULATE([Total Sales], Sales[Category] = "Accessories"), you get Accessories sales — the slicer's filter on Category is gone, overridden entirely.

Example 1: Overriding an existing filter

Say you want a measure that always shows Bikes sales, regardless of what category a user has filtered to elsewhere on the report — useful for a "benchmark" column next to whatever category the user is currently viewing.

Total Sales = SUM(Sales[SalesAmount])

Bikes Sales (Benchmark) =
CALCULATE(
    [Total Sales],
    Sales[Category] = "Bikes"
)

Drop both measures into a matrix with Category on rows. Total Sales changes per row, as expected — filter context comes from the matrix. Bikes Sales (Benchmark) shows the exact same number on every row, because the CALCULATE filter argument overrides whatever category the row context of the matrix contributes. This is the simplest and most common use of CALCULATE: replacing one filter with another, explicit one.

Example 2: Percent of total (removing filters with ALL)

Percent-of-total is a PL-300 favourite because it forces you to understand ALL — a table function that removes filters instead of applying new ones.

Total Sales = SUM(Sales[SalesAmount])

% of All Sales =
DIVIDE(
    [Total Sales],
    CALCULATE([Total Sales], ALL(Sales))
)

Here, ALL(Sales) inside CALCULATE clears every filter currently applied to the Sales table — category, region, date, whatever the report has active — and evaluates [Total Sales] against the unfiltered table. That gives you the grand total, no matter which row or visual the measure is evaluated in. DIVIDE (always prefer it over the / operator — it handles divide-by-zero cleanly) then compares the row's filtered total against that constant grand total.

A common mistake here is using ALL(Sales[Category]) instead of ALL(Sales) when you actually want the grand total across every column, not just category. ALL on a single column only removes the filter from that column — filters on region or date would still apply. Read the requirement carefully; the exam tests this distinction directly.

Example 3: Context transition (the one that separates passing candidates)

This is the concept that trips up even experienced Power BI users, because it's invisible unless you know to look for it. Say you want to flag which products are priced above the average for their own category — a classic PL-300 scenario question.

Products Above Category Average =
CALCULATE(
    COUNTROWS(Product),
    FILTER(
        Product,
        Product[ListPrice] >
            CALCULATE(
                AVERAGE(Product[ListPrice]),
                ALLEXCEPT(Product, Product[Category])
            )
    )
)

Walk through the inner CALCULATE carefully, because this is where context transition happens. FILTER(Product, ...) iterates the Product table row by row — for each row, DAX is in row context: it knows the current product, but a plain AVERAGE(Product[ListPrice]) inside that row context would just average the entire table, ignoring which row you're on. That's not what we want.

The inner CALCULATE fixes this. Whenever CALCULATE is evaluated inside a row context, DAX automatically converts that row context into an equivalent filter context — this is context transition, and it happens every time you wrap an aggregation in CALCULATE inside an iterator. So for the product currently being evaluated, its Category value becomes a filter. Then ALLEXCEPT(Product, Product[Category]) removes every other filter on Product while explicitly keeping the category filter that context transition just created — the result is "average list price within this product's category." Each product then gets compared against its own category's average, not the grand average.

This is also why measures — not just explicit CALCULATE calls — trigger context transition. Any measure reference inside a row context (a calculated column, or an iterator like SUMX) is implicitly wrapped in CALCULATE, which is why calculated columns referencing measures often behave differently than people expect.

Why this matters beyond the exam

In real reports, almost everything interesting — year-over-year growth, rank within a group, "top N" flags, security filters — is a variation of these three patterns: override a filter, remove a filter, or transition row context into filter context. Once you can read a CALCULATE expression and identify which of the three it's doing, unfamiliar DAX stops being intimidating. That's the actual skill PL-300 is testing, and it's the same skill you'll use every week once you're building real models.

Want to work through DAX like this every week?

Gyromitra's PL-300 membership pairs the full self-paced course with a live weekly Q&A with a Microsoft Certified Trainer — bring your own CALCULATE questions. Join anytime, no cohort to wait for.