Power BI Lesson 36 – CALCULATE Function | Dataplexa
DAX · Lesson 36

CALCULATE in Depth

CALCULATE is the engine of advanced DAX. Every time you need a measure that ignores a filter, adds a filter, swaps out a filter, or compares a value against a different period or a different subset of data — CALCULATE is doing the work. This lesson covers every filter modifier, how multiple filter arguments interact, the common patterns professionals use every day, and the edge cases that produce wrong results silently.

The Working Dataset

Orders table — used for all examples
OrderIDRevenueRegionStatusCustomerTierOrderDate
10011,200NorthDeliveredPremium2024-01-05
1002850SouthProcessingStandard2024-01-18
1003430NorthLatePremium2024-02-03
100495SouthLateStandard2024-02-14
10051,540WestShippedPremium2024-02-20
Grand totals: Revenue = 4,115 · Premium rows = 1001,1003,1005 (rev 3,170) · North = 1001,1003 (rev 1,630) · South = 1002,1004 (rev 945) · West = 1005 (rev 1,540)

CALCULATE Anatomy

CALCULATE takes an expression and zero or more filter arguments. It first modifies the filter context using those arguments, then evaluates the expression in the modified context. The modifications apply only to the expression inside CALCULATE — they do not affect anything outside it.

CALCULATE anatomy
CALCULATE(
    SUM(Orders[Revenue]),   -- expression
    Orders[Region] = "North",  -- filter 1 (replaces Region filter)
    Orders[CustomerTier] = "Premium" -- filter 2 (adds Tier filter)
)
The function itself
Expression to evaluate
Filter 1 — column = value
Filter 2 — adds another condition

How Filter Arguments Interact

Each filter argument in CALCULATE follows a specific rule depending on whether the column it targets already has a filter in the current context. Understanding these rules prevents the most common CALCULATE mistakes.

Situation What CALCULATE does Example
Column has no existing filter The filter argument is added to the context — it intersects with all other active filters. No Tier filter active → CALCULATE adds Tier=Premium. Now only Premium rows are visible.
Column already has a filter (e.g. from a slicer) The filter argument replaces the existing filter on that column — it does not add to it. The slicer's filter is overridden for the expression. Slicer = North, then CALCULATE adds Region="West" → the Region="North" filter is replaced by Region="West". Expression sees only West rows.
Multiple filters on different columns All filter arguments are applied simultaneously. They intersect — a row must satisfy every filter condition to be included. CALCULATE(SUM, Region="North", Tier="Premium") → only North AND Premium rows. Result: 1,200 + 430 = 1,630 but only if Premium → 1,200 (1003 is Premium but low rev → 1,630 total).
Filter modifier functions (ALL, ALLSELECTED…) These do not add filters — they remove existing ones from the context before the expression evaluates. Covered in the next section. CALCULATE(SUM, ALL(Orders[Region])) → removes Region filter entirely, expression sees all regions.

Filter Modifier Functions

Filter modifiers are functions used exclusively as arguments inside CALCULATE. They control which existing filters are kept, removed, or overridden. Mastering these four functions gives you complete control over what the expression inside CALCULATE is allowed to see.

// ALL(table_or_column)
// Removes ALL filters from a table or a specific column
Grand Total =
    CALCULATE(SUM(Orders[Revenue]), ALL(Orders))
// Ignores every filter — slicer, visual, page — returns 4,115 always

All Regions Revenue =
    CALCULATE(SUM(Orders[Revenue]), ALL(Orders[Region]))
// Removes Region filter only — other filters (Tier, Status) still apply
Grand Total and All Regions Revenue — table visual with Region on rows, Tier slicer = Premium
Region Total Revenue Grand Total (ALL Orders) All Regions (ALL Region)
North1,6304,1153,170
West1,5404,1153,170
Total3,1704,1153,170
Slicer=Premium filters South out (no Premium rows there) · ALL(Orders) ignores slicer entirely → always 4,115 · ALL(Orders[Region]) removes Region filter but keeps Tier=Premium → 3,170 (Premium rows only, all regions)
// ALLSELECTED(table_or_column)
// Removes visual-level row/column filters but KEEPS slicer filters
// The "% of total within slicer" workhorse

Revenue % of Total =
    DIVIDE(
        SUM(Orders[Revenue]),
        CALCULATE(SUM(Orders[Revenue]), ALLSELECTED(Orders))
    )
Revenue % of Total — slicer = North + South (West excluded)
Region Revenue % using ALL (wrong) % using ALLSELECTED (correct)
North1,63039.6%63.3%
South94523.0%36.7%
Total2,57562.6% ❌100.0% ✓
ALL denominator = 4,115 (ignores slicer) → percentages don't sum to 100% · ALLSELECTED denominator = 2,575 (respects slicer) → percentages sum to 100% within the selection
// ALLEXCEPT(table, column_to_keep1, column_to_keep2, ...)
// Removes all filters EXCEPT from the specified columns
// Useful when you want to aggregate across one dimension
// while keeping all other filters intact

Revenue Ignoring Status =
    CALCULATE(
        SUM(Orders[Revenue]),
        ALLEXCEPT(Orders, Orders[Region], Orders[CustomerTier])
        -- Removes filters from ALL columns EXCEPT Region and Tier
        -- Status filter is removed; Region and Tier filters stay
    )
Revenue Ignoring Status — Region on rows, Status slicer = Late
Region Revenue (Status=Late) Revenue Ignoring Status
North4301,630
South95945
Total5252,575
Status=Late filter removed by ALLEXCEPT · Region filter kept · each region shows its full revenue regardless of status · useful for "late orders vs all orders in that region" comparisons
// KEEPFILTERS(filter_expression)
// Adds a filter WITHOUT replacing an existing one on the same column
// Result = intersection of the existing filter AND the new filter

North Revenue (KEEPFILTERS) =
    CALCULATE(
        SUM(Orders[Revenue]),
        KEEPFILTERS(Orders[Region] = "North")
    )
// Normal CALCULATE with Region="North":
//   Replaces any existing Region filter → always returns North revenue
// KEEPFILTERS with Region="North":
//   Intersects with existing Region filter
//   When visual row = South: South ∩ North = empty → BLANK
//   When visual row = North: North ∩ North = North → 1,630
//   When no row filter: no existing filter ∩ North = North → 1,630
CALCULATE vs KEEPFILTERS — Region on rows
Region (row) Total Revenue CALCULATE Region="North" (replaces) KEEPFILTERS Region="North" (intersects)
North1,6301,6301,630
South9451,630BLANK
West1,5401,630BLANK
Total4,1151,6301,630
CALCULATE replaces Region filter → North revenue appears in every row · KEEPFILTERS intersects → only the North row shows a value; South and West have no intersection → BLANK
// REMOVEFILTERS(table_or_column) — explicit alias for ALL()
// Clearer intent in some scenarios — "I am removing filters" vs "ALL"
Revenue No Region Filter =
    CALCULATE(
        SUM(Orders[Revenue]),
        REMOVEFILTERS(Orders[Region])
    )
// Identical to: CALCULATE(SUM(Orders[Revenue]), ALL(Orders[Region]))
REMOVEFILTERS — Revenue No Region Filter (same as ALL on column)
Region Total Revenue Revenue No Region Filter
North1,6304,115
South9454,115
West1,5404,115
Total4,1154,115
Region filter removed — expression sees all rows in every cell · other filters (Tier, Status, etc.) would still apply if active

The FILTER() Function Inside CALCULATE

When a filter condition cannot be expressed as a simple column=value, use FILTER() to create a table of matching rows and pass that table as the filter argument. FILTER() is an iterator — it evaluates the condition row by row. This is more powerful but slower than a direct column filter.

// When to use FILTER() instead of column = value

// Simple condition — use direct column filter (faster)
North Revenue = CALCULATE(SUM(Orders[Revenue]), Orders[Region] = "North")

// Condition involving a measure — MUST use FILTER()
// (measures cannot be used directly as CALCULATE filter arguments)
High Value Revenue =
    CALCULATE(
        SUM(Orders[Revenue]),
        FILTER(
            Orders,
            Orders[Revenue] > AVERAGE(Orders[Revenue])
        )
    )
// FILTER iterates every row of Orders, keeps rows where
// Revenue > average Revenue. Returns those rows as a table.
// CALCULATE then evaluates SUM only over those filtered rows.
High Value Revenue — orders above average (avg = 823)
OrderID Revenue Above Avg? Included in High Value Revenue
10011,200✓ Yesincluded
1002850✓ Yesincluded
1003430✗ Noexcluded
100495✗ Noexcluded
10051,540✓ Yesincluded
High Value Revenue (total)3,590
Average = 823 · Orders 1001 (1200), 1002 (850), 1005 (1540) are above average · sum = 1200 + 850 + 1540 = 3,590

Common CALCULATE Patterns

// Pattern 1 — Conditional total (fixed segment regardless of context)
Premium Revenue =
    CALCULATE(SUM(Orders[Revenue]), Orders[CustomerTier] = "Premium")
// Returns Premium revenue in every cell — ignores Tier slicer
Premium Revenue — always shows Premium total regardless of Tier slicer
RegionTotal RevenuePremium Revenue
North1,6301,630
South945BLANK
West1,5401,540
Total4,1153,170
South has no Premium customers → BLANK · North and West intersect correctly with Premium filter
// Pattern 2 — Prior period comparison using VAR for clarity
Revenue vs Prior Month =
VAR CurrentRev = SUM(Orders[Revenue])
VAR PriorRev   =
    CALCULATE(
        SUM(Orders[Revenue]),
        DATEADD(Calendar[Date], -1, MONTH)
    )
RETURN
    CurrentRev - PriorRev
Revenue vs Prior Month — monthly view (Jan and Feb 2024)
MonthRevenuePrior Month Revenuevs Prior Month
Jan 20242,050BLANKBLANK
Feb 20242,0652,050+15
Jan has no prior month data → BLANK · Feb compares to Jan (orders 1001+1002 = 2,050) → Feb (orders 1003+1004+1005 = 2,065) → +15
// Pattern 3 — Multiple filter arguments (AND logic)
North Premium Revenue =
    CALCULATE(
        SUM(Orders[Revenue]),
        Orders[Region] = "North",
        Orders[CustomerTier] = "Premium"
    )
North Premium Revenue — two filter arguments (AND)
OrderIDRegionTierRevenueIncluded?
1001NorthPremium1,200
1002SouthStandard850
1003NorthPremium430
1004SouthStandard95
1005WestPremium1,540✗ (not North)
North Premium Revenue1,630(1001+1003)
// Pattern 4 — OR logic using FILTER (two values on same column)
Late or Processing Revenue =
    CALCULATE(
        SUM(Orders[Revenue]),
        FILTER(
            ALL(Orders[Status]),
            Orders[Status] = "Late" || Orders[Status] = "Processing"
        )
    )
// Note: multiple CALCULATE arguments = AND
// For OR on the same column, use FILTER() with || operator
// Alternative using IN operator:
Late or Processing Revenue =
    CALCULATE(
        SUM(Orders[Revenue]),
        Orders[Status] IN {"Late", "Processing"}
    )
Late or Processing Revenue — OR logic on Status
OrderIDStatusRevenueIncluded?
1001Delivered1,200
1002Processing850
1003Late430
1004Late95
1005Shipped1,540
Late or Processing Revenue1,375 (850+430+95)
IN operator is the cleanest syntax for OR on the same column — equivalent to FILTER with || but more readable

The CALCULATE Modifier Reference

Modifier Effect on filter context When to use
ALL(table) Removes all filters from the entire table including slicers Grand totals that must ignore all user selections
ALL(column) Removes filters from one column only; other columns unaffected Show all regions in a region-filtered context; RANKX denominators
ALLSELECTED(table) Removes row/column visual filters; keeps slicer and page filters % of total that resets within the user's slicer selection
ALLEXCEPT(tbl, col…) Removes all filters except from the specified columns Subtotal that ignores one dimension but keeps all others
KEEPFILTERS(expr) Intersects new filter with existing filter instead of replacing it Show value only for matching rows; return BLANK elsewhere
REMOVEFILTERS(col) Explicit alias for ALL() — removes filters from table or column Same as ALL(); use when intent ("removing filters") is clearer than "all"

Teacher's Note: The most important thing to know about CALCULATE is that it replaces filters on the same column by default — and this surprises almost every beginner the first time they see it. You write CALCULATE(SUM([Revenue]), Region="North") inside a slicer that has already selected North and South, expecting to see North revenue. You do see North revenue — but not because of the slicer. The Region="North" argument replaced the slicer's Region filter. If the user changes the slicer to South only, the measure still returns North revenue. Always ask: "Do I want to add to the existing context, or replace it?" If you want to add, use KEEPFILTERS. If you want to override, the default behaviour is what you want.

Practice

Practice 1 of 3

To build a Revenue % of Total measure where the denominator respects the user's slicer but ignores the visual's row grouping — so percentages always sum to 100% within whatever is selected — you use CALCULATE with ___(Orders) as the filter modifier.

Practice 2 of 3

When CALCULATE receives two filter arguments targeting different columns — for example Region="North" and Tier="Premium" — the resulting filter context applies both conditions as a logical ___ — only rows satisfying both are included.

Practice 3 of 3

When you need to apply an OR condition on the same column inside CALCULATE — for example including Status = "Late" OR Status = "Processing" — you either use the ___ operator with a list like Orders[Status] IN {"Late","Processing"} or wrap the condition in FILTER().

Lesson Quiz

Quiz 1 of 3

A report has a Region slicer. You write North Revenue = CALCULATE(SUM([Revenue]), Orders[Region]="North"). When a user selects South in the slicer, what does North Revenue return?

Quiz 2 of 3

You need a measure that shows each region's revenue as a % of the total across all five orders — but when the user applies a Tier slicer to show Premium only, the percentages should recalculate to sum to 100% within Premium. Which formula is correct?

Quiz 3 of 3

You write Revenue = CALCULATE(SUM([Revenue]), Orders[Status]="Late", Orders[Status]="Processing") expecting to get revenue for Late OR Processing orders. What actually happens and how do you fix it?

Next up — Lesson 37 covers Time Intelligence, including every DATEYTD, SAMEPERIODLASTYEAR, DATEADD, and running total pattern, and exactly how the Calendar table relationship enables these functions to work.