DAX practice questions with answers

Updated October 9, 2026

Fifteen free DAX practice questions with explained answers, written as short scenarios on measures, filter context, CALCULATE and iterators. DAX is the formula language of Power BI, Analysis Services and Fabric semantic models, and each question states its tables, relationships and sample values so that the result can be worked out by hand. The topic is tested in PL-300 and DP-600.

How to use these questions

Read the model description first and sketch the relationship direction. Then work out which filters are active in the cell the stem asks about, and commit to one letter before opening the explanation. Underline the constraint word, such as “respond to slicers”, “percent of selected”, “each product” or “contiguous”, because it usually decides between a measure, an iterator and a filter modifier. The guide DAX basics: filter context and CALCULATE explains the mechanism behind the answers.

Warm-up: measures, columns and relationships

Question 1. The table Sales has the columns Profit and Amount. Two lines exist: Profit 20 with Amount 100, and Profit 10 with Amount 10. A report must show the overall margin, which must be correct at every subtotal and respond to slicers. Which approach is correct?

  • A. A calculated column Margin = DIVIDE ( Sales[Profit], Sales[Amount] ) that is summed in the visual
  • B. The same calculated column Margin, averaged in the visual
  • C. Margin % = DIVIDE ( SUM ( Sales[Profit] ), SUM ( Sales[Amount] ) ) as a measure
  • D. Margin % = SUM ( Sales[Profit] / Sales[Amount] ) as a measure
Show answer

Answer: C

A measure that divides the sum of Profit by the sum of Amount is evaluated per cell, so it gives 30 / 110, about 27.3 percent, for the two lines together. Summing a per-line ratio column gives 20 percent plus 100 percent, which is 120 percent. Averaging the ratio column gives 60 percent, because it ignores how large each line is. SUM accepts a single column, so SUM of Profit divided by Amount is not a valid expression.

Question 2. The table Sales has the columns Quantity and UnitPrice, with no Amount column. Two lines exist: Quantity 2 at UnitPrice 10, and Quantity 3 at UnitPrice 5. Which measure returns the total revenue of 35?

  • A. SUMX ( Sales, Sales[Quantity] * Sales[UnitPrice] )
  • B. SUM ( Sales[Quantity] ) * SUM ( Sales[UnitPrice] )
  • C. SUM ( Sales[Quantity] * Sales[UnitPrice] )
  • D. COUNTROWS ( Sales ) * AVERAGE ( Sales[UnitPrice] )
Show answer

Answer: A

SUMX is an iterator: it evaluates Quantity times UnitPrice for each line (20 and 15) and adds the results, giving 35. Multiplying the two sums gives 5 times 15, which is 75. SUM takes a single column reference, so SUM over a product of two columns is invalid. The row count times the average price gives 2 times 7.5, which is 15.

Question 3. The model has Product (ProductKey, Category) with 3 rows and Sales (ProductKey, Channel, Amount). One Product row relates to many Sales rows, and the filter direction is single, from Product to Sales. A table visual shows Sales[Channel] (Online, Store) with the measure Products = COUNTROWS ( Product ). Both rows show 3. Why?

  • A. COUNTROWS ignores all filters
  • B. Channel must be moved to the Product table first
  • C. The measure must use DISTINCTCOUNT
  • D. The filter on Sales[Channel] does not propagate to Product
Show answer

Answer: D

A filter on Sales[Channel] filters only the Sales table. With a single-direction relationship the filter travels from Product to Sales, never from Sales to Product, so the Product table remains unfiltered and COUNTROWS returns all 3 rows in every cell. COUNTROWS does not ignore filters on its own table. Moving the column or changing the aggregation does not change the direction in which filters propagate.

Question 4. The table Sales has the columns CustomerKey, OrderID and Amount, with one row per order line. A card must show how many different customers bought something in the current filter context. Which measure is correct?

  • A. COUNT ( Sales[CustomerKey] )
  • B. DISTINCTCOUNT ( Sales[CustomerKey] )
  • C. COUNTROWS ( Sales )
  • D. SUM ( Sales[CustomerKey] )
Show answer

Answer: B

DISTINCTCOUNT counts the different values of a column, so a customer with ten order lines is counted once. COUNT counts the non-blank values, which is the number of order lines. COUNTROWS counts the rows of the table, which is also the number of lines. SUM adds the key values, which has no meaning.

Question 5. Sales (ProductKey, Amount) is on the many side of a relationship to Product (ProductKey, Category). A new calculated column in Sales must show the category of each line. Which expression works?

  • A. RELATEDTABLE ( Product )
  • B. SUM ( Product[Category] )
  • C. RELATED ( Product[Category] )
  • D. VALUES ( Product[Category] )
Show answer

Answer: C

RELATED follows the many-to-one relationship from the current Sales row to the matching Product row and returns the Category value. RELATEDTABLE returns a table and is used from the one side to reach the many side. SUM cannot aggregate a text column. VALUES returns a table of distinct values and, in a row context, does not follow the relationship to filter itself, so it does not return a single category per line.

Scenarios: CALCULATE, filter modifiers and dates

Question 6. Product (Category) relates one-to-many to Sales (Amount), and Total Sales = SUM ( Sales[Amount] ). Sales per category are Bikes 600, Clothing 300 and Accessories 100. A slicer on Product[Category] selects Bikes and Clothing, and a matrix shows Category on the rows. Which measure shows Bikes as 66.7 percent, its share of the selected categories?

  • A. DIVIDE ( [Total Sales], CALCULATE ( [Total Sales], ALLSELECTED ( Product[Category] ) ) )
  • B. DIVIDE ( [Total Sales], CALCULATE ( [Total Sales], REMOVEFILTERS ( Product[Category] ) ) )
  • C. DIVIDE ( [Total Sales], CALCULATE ( [Total Sales], Product[Category] = "Bikes" ) )
  • D. DIVIDE ( [Total Sales], [Total Sales] )
Show answer

Answer: A

ALLSELECTED on the Category column removes the row filter created by the matrix but keeps the slicer selection, so the denominator is 900 and Bikes shows 600 / 900, which is 66.7 percent. REMOVEFILTERS on Category also removes the slicer, so the denominator is 1,000 and Bikes shows 60 percent. A filter that sets the category to Bikes makes the denominator 600 and the result 100 percent. Dividing the measure by itself is always 100 percent.

Question 7. Same model: Total Sales per category is Bikes 600, Clothing 300 and Accessories 100, and the matrix has Category on the rows with a grand total row. A measure is defined as CALCULATE of Total Sales with KEEPFILTERS wrapped around the filter Product[Category] equals Bikes. What do the Bikes row, the Clothing row and the grand total row show?

  • A. Bikes 600, Clothing 600, total 600
  • B. Bikes 600, Clothing blank, total 600
  • C. Bikes 600, Clothing blank, total 1,000
  • D. All three cells blank
Show answer

Answer: B

KEEPFILTERS adds the new filter without overwriting the existing one, so the two are intersected. In the Bikes row the result is 600. In the Clothing row the Clothing filter and the Bikes filter have no category in common, so the result is blank. In the grand total row no category filter exists, so the Bikes filter is simply added and the result is 600. Without KEEPFILTERS the Clothing row would be overwritten and show 600 as well.

Question 8. Product (ProductName) relates one-to-many to Sales (Amount). Sales per product are Road bike 600, Helmet 300 and Gloves 100. A calculated column in the Product table must show each product's own sales, so Road bike shows 600. Which expression is correct?

  • A. SUM ( Sales[Amount] )
  • B. SUMX ( Sales, Sales[Amount] )
  • C. COUNTROWS ( Sales )
  • D. CALCULATE ( SUM ( Sales[Amount] ) )
Show answer

Answer: D

A calculated column runs in a row context, and CALCULATE converts that row into a filter on Product, which flows to Sales through the relationship, so SUM then adds only that product’s lines. A plain SUM ignores the row context and returns 1,000 in every row. SUMX over the whole Sales table is also not filtered by the Product row and returns 1,000. COUNTROWS of Sales returns the number of lines, not an amount, and is unfiltered too.

Question 9. The date table was built from the distinct values of Sales[OrderDate], so days without orders are missing. It is related to Sales and used in the measure Sales LY = CALCULATE ( [Total Sales], SAMEPERIODLASTYEAR ( 'Date'[Date] ) ), which returns wrong or missing values. What fixes the problem?

  • A. Change the relationship to bidirectional
  • B. Convert the measure into a calculated column
  • C. Create a calendar table with every date and mark it as the date table
  • D. Wrap the measure in ALL ( Sales )
Show answer

Answer: C

Time intelligence functions need a date table with one row for every day of the period and no gaps. Creating a calendar table that covers all dates and marking it as the date table fixes the measure. A bidirectional relationship changes filter propagation, not the gaps in dates. Turning the measure into a calculated column removes its response to filters. Wrapping the measure in ALL on Sales removes filters and cannot restore missing dates.

Question 10. Sales has two date columns, OrderDate and ShipDate, and both relate to 'Date'[Date]. The relationship on OrderDate is active and the one on ShipDate is inactive. Which measure returns the sales amount by ship date for the Date table in the visual?

  • A. CALCULATE ( [Total Sales], 'Date'[Date] = Sales[ShipDate] )
  • B. CALCULATE ( [Total Sales], USERELATIONSHIP ( Sales[ShipDate], 'Date'[Date] ) )
  • C. CALCULATE ( [Total Sales], ALL ( 'Date' ) )
  • D. SUMX ( Sales, Sales[Amount] )
Show answer

Answer: B

USERELATIONSHIP activates the inactive relationship for the duration of the CALCULATE, so the Date table filters Sales by ShipDate. Comparing Date[Date] with Sales[ShipDate] in a Boolean filter references two tables, which is not allowed. ALL on the Date table removes the date filter, so every cell returns the grand total. A plain SUMX still uses the active OrderDate relationship.

Edge cases and traps: division, variables, iterators and snapshots

Question 11. The measure Margin % = DIVIDE ( SUM ( Sales[Profit] ), SUM ( Sales[Amount] ) ) is shown in a matrix by product. For one product, Profit is 0 and Amount is 0. What does the cell show?

  • A. Blank
  • B. 0
  • C. An error
  • D. NaN
Show answer

Answer: A

DIVIDE returns the alternate result when the denominator is zero, and the alternate result defaults to BLANK when none is given, so the cell is blank. It does not return 0, because 0 is returned only if it is passed as the third argument. It does not raise an error, which is the purpose of DIVIDE. NaN is what the plain division operator can produce for 0 divided by 0.

Question 12. Product (Category) relates one-to-many to Sales, and Total Sales per category is Bikes 600, Clothing 300 and Accessories 100. A measure is defined as VAR s = [Total Sales] RETURN CALCULATE ( s, REMOVEFILTERS ( Product ) ), and a matrix shows Category on the rows. What does the Bikes row show?

  • A. 1,000
  • B. Blank
  • C. An error, because CALCULATE needs a measure
  • D. 600
Show answer

Answer: D

A variable is evaluated once, in the filter context where it is defined, and keeps that value. In the Bikes row s is 600 before CALCULATE runs, so removing filters afterwards cannot change it. The row therefore shows 600, and the Clothing row shows 300. It would show 1,000 only if the measure itself were inside CALCULATE. It is not blank, and a variable holding a value is a valid first argument of CALCULATE.

Question 13. Product (ProductName) relates one-to-many to Sales, and Total Sales = SUM ( Sales[Amount] ). Sales per product are Road bike 600, Helmet 300 and Gloves 100. A card must show the sales of only those products whose own sales exceed 250, which is 900. Which measure returns it?

  • A. CALCULATE ( [Total Sales], FILTER ( Product, [Total Sales] > 250 ) )
  • B. CALCULATE ( [Total Sales], [Total Sales] > 250 )
  • C. IF ( [Total Sales] > 250, [Total Sales] )
  • D. FILTER ( Product, [Total Sales] > 250 )
Show answer

Answer: A

FILTER iterates over Product, and referencing the measure inside the iterator triggers context transition, so each product is tested on its own sales. Road bike and Helmet pass, and CALCULATE then sums their lines to 900. A Boolean filter in CALCULATE cannot reference a measure. IF tests the total of 1,000 once, which passes, and returns 1,000. FILTER on its own returns a table, which a measure cannot return as its result.

Question 14. The table Inventory (Date, ProductKey, Stock) is a daily snapshot and relates to a marked date table 'Date'. For the product Widget it holds only two rows: 1 January with Stock 14 and 31 January with Stock 10. A matrix shows the month January. Which measure shows the month-end stock of 10?

  • A. SUM ( Inventory[Stock] )
  • B. AVERAGE ( Inventory[Stock] )
  • C. CALCULATE ( SUM ( Inventory[Stock] ), LASTDATE ( 'Date'[Date] ) )
  • D. MAX ( Inventory[Stock] )
Show answer

Answer: C

Stock is a semi-additive value and must not be summed over days. LASTDATE returns the last date in the current filter context, 31 January, and CALCULATE evaluates the sum on that day only, which gives 10. SUM adds both snapshots and gives 24. AVERAGE gives 12. MAX gives 14, which happens to be the highest value, not the month-end value.

Question 15. The table Fuel has the columns Litres and PricePerLitre. Two purchases exist: 10 litres at a price of 2.00, and 90 litres at a price of 1.00. Which measure returns the correct average price paid per litre of 1.10?

  • A. AVERAGE ( Fuel[PricePerLitre] )
  • B. DIVIDE ( SUMX ( Fuel, Fuel[Litres] * Fuel[PricePerLitre] ), SUM ( Fuel[Litres] ) )
  • C. AVERAGEX ( Fuel, Fuel[Litres] * Fuel[PricePerLitre] )
  • D. SUM ( Fuel[PricePerLitre] ) / SUM ( Fuel[Litres] )
Show answer

Answer: B

The price paid per litre is total cost divided by total litres: (10 times 2.00 plus 90 times 1.00) / 100 = 110 / 100 = 1.10. SUMX builds the total cost row by row and DIVIDE divides by the litres. AVERAGE of the price gives 1.50 because it ignores the volumes. AVERAGEX of the cost per row gives 55, the average cost per purchase. Dividing the sum of prices by the litres gives 0.03.

Where to go next

Review the theory in DAX basics: filter context and CALCULATE, then continue with KQL practice questions and Delta Lake and Spark practice questions. The free 20-question PL-300 practice test mixes DAX with the rest of the exam, and multiple-choice exam tips cover how to handle the constraint words.