Forum Discussion

EfratY's avatar
EfratY
New Member
5 months ago
Solved

DAX Behavior

  Hi everyone, I’m trying to understand a behavior in DAX and would appreciate your help. Here are my measures:   Total Orders = DISTINCTCOUNT( 'Sales Data'[OrderNumber] ) Aver...
  • OwenAuger's avatar
    5 months ago

    HI EfratY 

    Here are the main points explaining what's going on:

    1. Any measure reference in DAX is automatically wrapped in a hidden CALCULATE.
      In this case, [Average Retail Price] is treated as CALCULATE ( [Average Retail Price] ).
    2. Calling the CALCULATE function within a row context causes context transition, where the row context is transformed into an equivalent filter context before evaluating the first argument of CALCULATE.
    3. In the High Ticket Orders measure, the FILTER function is an iterator which iterates over 'Product Lookup', evaluating the 2nd argument expression Product Lookup'[ProductPrice] > [Average Retail Price] within a row context corresponding to each row of 'Product Lookup'.
    4. Due to this context transition, the values of all columns of 'Product Lookup' in the "current row", including 'Product Lookup'[ProductPrice], are added as filters when evaluating [Average Retail Price]. This means [Average Retail Price] will return the average of just the single price on the current row iterated by FILTER. In other words [Average Retail Price] will return the same value as 'Product Lookup'[ProductPrice] for any given row of 'Product Lookup' iterated by FILTER.
    5. As a result, 'Product Lookup'[ProductPrice] > [Average Retail Price] is logically equivalent to 'Product Lookup'[ProductPrice] > 'Product Lookup'[ProductPrice], which is always false (a value is never greater than itself).
    6. If you replace [Average Retail Price] with [Overall Average Price], context transition still happens, but [Overall Average Price] removes filters on 'Product Lookup' via ALL ( 'Product Lookup' ) so the filters due to context transition are ignored. The value returned by [Overall Average Price] would however ignore any existing filters on 'Product Lookup' so would not change due to any existing filters on 'Product Lookup'.
    7. Suggested solution: I would generally recommend storing the value of [Average Retail Price] in a variable before calling FILTER. This avoids the whole context transition complication and should return the intended value. I would also recommend changing FILTER ( ... ) to a boolean condition within KEEPFILTERS. See below:
    High Ticket Orders improved v1 =
    VAR AveragePrice = [Average Retail Price]
    RETURN
        CALCULATE (
            [Total Orders],
            FILTER (
                'Product Lookup',
                'Product Lookup'[ProductPrice] > AveragePrice
            )
        )
    High Ticket Orders improved v2 =
    VAR AveragePrice = [Average Retail Price]
    RETURN
        CALCULATE (
            [Total Orders],
            KEEPFILTERS ( 'Product Lookup'[ProductPrice] > AveragePrice )
        )
    

     

    Some good reading on this topic:

    https://www.sqlbi.com/articles/understanding-context-transition-in-dax/