1. Lighthouse

Level 4 · Filter by a measure with FILTER

The request

From Jessica Moore, Marketing Analyst

“We're testing free white-glove delivery on orders over $500. Before we commit, I need to know how much of December's revenue came from orders that size, per channel. The order total, not single lines: a $300 sofa plus a $250 rug is a $550 order.”

Your goal

The matrix has orders[channel] on its rows and a 'Date'[Year Month] slicer set to 2025-12. Create a measure called Big Order Sales: Sales from completed orders whose own Sales is above 500. Use CALCULATE with FILTER over VALUES(orders[order_id]).

  • Fill [Big Order Sales] on every row of the visualnot done yet
  • The Total row right toonot done yet

Your measure

DAX
Visual
A matrix: rows = orders[channel]; values = [Sales], [Big Order Sales]
Slicers
'Date'[Year Month] = 2025-12
Measures in the report
Sales = CALCULATE(SUM(order_items[line_total]), orders[status] = "completed")
Data pane: tables and columns
  • order_items order_item_id, order_id, product_id, quantity, unit_price, discount_pct, line_total
  • orders order_id, customer_id, order_date, status, channel, shipping_fee, coupon_code
  • products product_id, name, category, subcategory, unit_price, unit_cost, launched_on, is_active
  • customers customer_id, first_name, last_name, email, city, state, signup_date, segment, referral_source
  • returns return_id, order_item_id, returned_on, reason, refund_amount
  • Date Date, Year, Quarter, Month Number, Month, Year Month, Year Quarter, Day, Weekday Number, Weekday

Loading the editor…

    Visual[Big Order Sales] fills in when you press Check
    The visual before your answer
    channelSalesBig Order Sales
    app$130,426
    marketplace$45,739
    web$112,181
    Total$288,346

    Mote checks your result

    Press Check. Mote fills in your answer and compares it with what the report needs.

    The lesson

    A boolean filter such as orders[status] = "completed" tests a column. Jessica’s condition is different: an order counts when its total is above $500, and the total is a measure computed from many order lines. For that you need a table filter built with FILTER.

    What you are working in

    This page runs a practice DAX engine built for this site. It evaluates your measure in each cell of the matrix and checks it. In Power BI Desktop: Home → New measure, type the formula, and add a slicer on 'Date'[Year Month] set to 2025-12 next to the matrix.

    FILTER returns a table

    FILTER(VALUES(orders[order_id]), [Sales] > 500)
    • VALUES(orders[order_id]) returns the order ids visible in the current filter context: one channel, one month. It is a one-column table.
    • FILTER(table, condition) is an iterator: it evaluates the condition once per row and keeps the rows where it is true.
    • [Sales] > 500 is evaluated for one order at a time. When a measure is called inside an iterator, DAX turns the current row into a filter first (context transition), so [Sales] sees only that order’s lines.

    The result is a table of order ids. Passed to CALCULATE, it becomes a filter like any other:

    Big Order Sales =
    CALCULATE(
        [Sales],
        FILTER(VALUES(orders[order_id]), [Sales] > 500)
    )

    Why not a boolean filter?

    CALCULATE([Sales], [Sales] > 500) is refused: a boolean filter must be about columns, and [Sales] is a measure whose value depends on context. And order_items[line_total] > 500 is a valid filter that answers a different question: it keeps expensive lines, so a $550 order made of two cheaper items drops out.

    Iterate the smallest table

    FILTER does real work for every row it visits. Here it visits at most about 330 December orders per cell. FILTER(order_items, …) with a measure inside would visit every order line, each with its own context transition, which is what makes reports crawl. VALUES of a key column on the “one” side gives the same answer with far fewer steps. The same advice holds in Power BI: never FILTER a whole fact table when a column will do.

    Common mistakes

    • FILTER(orders, …) instead of VALUES(orders[order_id]). It gives the same number here, but it iterates whole rows and turns every column of orders into a filter. That is heavier, and it gets hard to predict once other measures start removing filters. One key column is enough.
    • Using the measure outside CALCULATE. FILTER(…) alone is a table, not a number. It has to sit inside CALCULATE (or a function such as COUNTROWS).
    • Testing lines instead of orders. Read the ticket: “orders over $500” is about totals.

    Pick what may run on this site. You can change this any time from "Cookie settings" at the bottom of every page.