The request

From Patrick Owens, Chief Operating Officer
Your goal
Step 1 of 3. Step 1. The old Discounted Sales is in the editor as a comment. Write Discounted Sales again with the same numbers (completed orders, lines with discount_pct above 0, sum of order_items[line_total]) using CALCULATE with column filters and no FILTER. The matrix has 'Date'[Year] on its rows.
- Fill
[Discounted Sales]on every row of the visualnot done yet - The Total row right toonot done yet
Step 2 of 3. Step 2. Keep Discounted Sales and add Discounted Share = Discounted Sales ÷ Sales, blank when Sales isn't above zero. Store both measures in variables so each is evaluated once.
- Fill
[Discounted Share]on every row of the visualnot done yet - The Total row right toonot done yet
Step 3 of 3. Step 3. The Source step is every order line of 8 December 2025, as imported from SQL Server with all its columns. The report only needs discounted lines: keep rows with discount_pct above 0, and keep only order_id, product_id, quantity and discount_pct, in that order.
- Show exactly
order_idproduct_idquantitydiscount_pctnot done yet - 14 rowsnot done yet
Step 1 · your measure
- Visual
- A matrix: rows = 'Date'[Year]; values = [Sales], [Discounted Sales]
- 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…
Reference solution
| Year | Sales | Discounted Sales |
|---|---|---|
| 2,023 | 1,600,510.52 | |
| 2,024 | 1,993,604.39 | |
| 2,025 | 2,300,169.53 | |
| Total | 5,894,284.44 |
Mote checks your result
Press Check. Mote fills in your answer and compares it with what the report needs.
Step 2 · your measure
- Visual
- A matrix: rows = 'Date'[Year]; values = [Sales], [Discounted Share]
- 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…
Reference solution
| Year | Sales | Discounted Share |
|---|---|---|
| 2,023 | 1,600,510.52 | |
| 2,024 | 1,993,604.39 | |
| 2,025 | 2,300,169.53 | |
| Total | 5,894,284.44 |
Mote checks your result
Press Check. Mote fills in your answer and compares it with what the report needs.
Step 3 · your query steps
| order_item_id | order_id | product_id | quantity | unit_price | discount_pct | status | channel | |
|---|---|---|---|---|---|---|---|---|
| 1 | 28918 | 12448 | 135 | 6 | 159 | 0 | completed | app |
| 2 | 28919 | 12448 | 129 | 3 | 109 | 0 | completed | app |
| 3 | 28920 | 12448 | 180 | 2 | 20.99 | 0 | completed | app |
| 4 | 28921 | 12448 | 155 | 3 | 169 | 0 | completed | app |
| 5 | 28922 | 12449 | 185 | 1 | 12.99 | 10 | completed | web |
| 6 | 28923 | 12449 | 186 | 1 | 20.99 | 10 | completed | web |
| 7 | 28924 | 12449 | 198 | -1 | 44.99 | 10 | completed | web |
| 8 | 28925 | 12449 | 136 | 1 | 159 | 10 | completed | web |
| 9 | 28926 | 12450 | 185 | 1 | 12.99 | 0 | completed | web |
| 10 | 28927 | 12451 | 166 | 1 | 28.99 | 0 | completed | marketplace |
| 11 | 28928 | 12451 | 115 | 2 | 1599 | 0 | completed | marketplace |
| 12 | 28929 | 12452 | 118 | 1 | 1609 | 0 | completed | marketplace |
| 13 | 28930 | 12452 | 166 | 1 | 28.99 | 0 | completed | marketplace |
| 14 | 28931 | 12453 | 121 | 3 | 31.99 | 20 | completed | app |
| 15 | 28932 | 12454 | 160 | 1 | 70.99 | 0 | completed | app |
| 16 | 28933 | 12454 | 156 | 1 | 53.99 | 0 | completed | app |
| 17 | 28934 | 12454 | 180 | 1 | 20.99 | 0 | completed | app |
| 18 | 28935 | 12455 | 155 | 2 | 169 | 0 | completed | app |
| 19 | 28936 | 12455 | 166 | 2 | 28.99 | 0 | completed | app |
| 20 | 28937 | 12456 | 189 | 1 | 76.99 | 0 | completed | web |
| 21 | 28938 | 12456 | 198 | 2 | 44.99 | 0 | completed | web |
| 22 | 28939 | 12456 | 180 | 1 | 20.99 | 0 | completed | web |
| 23 | 28940 | 12456 | 193 | 1 | 19.99 | 0 | completed | web |
| 24 | 28941 | 12457 | 152 | 2 | 13.99 | 0 | completed | marketplace |
| 25 | 28942 | 12457 | 142 | 1 | 38.99 | 0 | completed | marketplace |
| 26 | 28943 | 12457 | 128 | 1 | 54.99 | 0 | completed | marketplace |
| 27 | 28944 | 12458 | 193 | 1 | 19.99 | 0 | completed | app |
| 28 | 28945 | 12458 | 146 | 1 | 16.99 | 0 | completed | app |
| 29 | 28946 | 12459 | 193 | 1 | 19.99 | 0 | completed | web |
| 30 | 28947 | 12460 | 173 | 2 | 139 | 0 | completed | web |
| 31 | 28948 | 12460 | 171 | 3 | 27.99 | 0 | completed | web |
| 32 | 28949 | 12460 | 138 | 2 | 199 | 0 | completed | web |
| 33 | 28950 | 12461 | 171 | 1 | 27.99 | 20 | completed | marketplace |
| 34 | 28951 | 12462 | 151 | 1 | 60.99 | 20 | completed | app |
| 35 | 28952 | 12462 | 166 | 1 | 28.99 | 20 | completed | app |
| 36 | 28953 | 12463 | 141 | 1 | 13.99 | 0 | completed | web |
| 37 | 28954 | 12464 | 182 | 2 | 17.99 | 0 | completed | web |
| 38 | 28955 | 12464 | 193 | 1 | 19.99 | 0 | completed | web |
| 39 | 28956 | 12464 | 122 | 1 | 29.99 | 0 | completed | web |
| 40 | 28957 | 12464 | 138 | 1 | 199 | 0 | completed | web |
| 41 | 28958 | 12465 | 151 | 2 | 60.99 | 20 | completed | web |
| 42 | 28959 | 12465 | 158 | 1 | 179 | 20 | completed | web |
| 43 | 28960 | 12465 | 190 | 1 | 43.99 | 20 | completed | web |
| 44 | 28961 | 12465 | 199 | 1 | 104.99 | 20 | completed | web |
| 45 | 28962 | 12466 | 130 | 1 | 409 | 0 | completed | web |
| 46 | 28963 | 12467 | 165 | 1 | 25.99 | 20 | completed | app |
| 47 | 28964 | 12467 | 157 | 4 | 109 | 20 | completed | app |
| 48 | 28965 | 12468 | 181 | 1 | 179 | 0 | completed | web |
| 49 | 28966 | 12468 | 193 | 3 | 19.99 | 0 | completed | web |
| 50 | 28967 | 12468 | 172 | 1 | 18.99 | 0 | completed | web |
| 51 | 28968 | 12469 | 140 | 2 | 329 | 0 | completed | marketplace |
| 52 | 28969 | 12469 | 110 | 1 | 179 | 0 | completed | marketplace |
Loading the editor…
Reference solution
Mote checks your result
Press Check. Mote fills in your answer and compares it with what the report needs.
What Patrick gets, and why
The lesson
Patrick’s report is slow for the usual three reasons at once: a measure that works row by row, a measure that repeats itself, and an import that carries far more than anyone reads. This case fixes all three, in the order you would at work.
What you are working in
A practice report and a practice Power Query editor, not Power BI. Steps 1 and 2 are DAX measures
checked cell by cell in a matrix with 'Date'[Year] on its rows; step 1 also checks that FILTER is
gone. Step 3 is a list of Applied Steps on the imported order lines, checked against the expected
table.
In Power BI Desktop: before you start, Optimize → Performance analyzer → Start recording → Refresh visuals and note the DAX query times. Edit the measures in the formula bar, open the query with Home → Transform data, and record again at the end.
Step 1: from FILTER to column filters
The old measure walks every order line, looks up the order’s status with RELATED, keeps the discounted completed lines, then sums them. Both conditions are plain tests on one column each, which is exactly what CALCULATE filter arguments are for:
Discounted Sales = CALCULATE(SUM(order_items[line_total]),
order_items[discount_pct] > 0, orders[status] = "completed")
The status filter on orders reaches order_items through the relationship, and the year on the
matrix rows reaches it through 'Date' → orders. Same numbers, one storage engine scan.
Step 2: a share without repeats
Discounted Share =
VAR discounted = [Discounted Sales]
VAR total = [Sales]
RETURN IF(total > 0, DIVIDE(discounted, total))
Each measure is evaluated once per cell and reused. DIVIDE protects the Total row and any year with no sales. Format it as a percentage in Power BI with Measure tools → Format → Percentage.
Step 3: import only discounted lines
The source brings eight columns for every line of the day. The report needs four, and only for discounted lines:
Filter rows: discount_pct > 0
Choose columns: order_id, product_id, quantity, discount_pct
Both steps fold into the SQL query that Power Query sends, so SQL Server returns the small result and Power BI never stores the rest. Filter first: once you choose the four columns, the filter still works here, but in real reports the column you filter on is often one you drop.
What to check afterwards
Record Performance analyzer again. The discount visuals’ DAX query time should drop, the refresh should be shorter, and the model smaller (DAX Studio’s View Metrics shows each table’s size). If one visual is still slow, its measure is next in line.
Lantern lit!
Practised: performancecalculatefiltervardividepower queryquery foldingboss
- Solved
- No hints
- First run
