Forum Discussion

brs09j's avatar
brs09j
Helper II
9 years ago
Solved

Context Transition

I'm sorry for all of these questions. This concept is really stumping me. Please let me know if what I gathered was incorrect. Thanks.   1)   Column = SUM ( Orders[Unit Price] ) will give you the...
  • mattbrice's avatar
    9 years ago

    There are 2 contexts in Dax.  A ROW context and a FILTER context.  Only the FILTER context is applied to the data model to change the foundset of rows against which the the aggregation measure is finally computed.  

     

    In your example #1, you had as a calculated COLUMN (not a measure) , Column = SUM ( Orders[Unit Price] ). Since this is a calculated column, the value is computed for each row one at the time.  For row #1, there is a row context which is the values of every column in the table for row #1.  But the filter context is empty.  Since there is a row context but no filter context, DAX sum's up all the values for 'Unit Price' is the Orders table. (Because, again, only Filter context impacts the model foundset, row context's do not).  For Row #2, Dax engine again sees a row context which is current values for every column in row #2.  But Filter context is again empty, so again DAX sum's up all the values for the 'Unit Price' in the Orders table.  In the end, for this new calculated column every row in the table will have the same value.

     

    In your example #2, you wrapped the calculated column in a CALCULATE statement.  One of the main features of CALCULATE is to trigger what is called a "context transition".  It removes the the values from the row context and puts them into the filter context.  So with Column = CALCULATE ( SUM ( Orders[Unit Price] ) ), all the values of the columns of the current row are transitioned into the Filter context.  The Filter context is then applied to the model, and the SUM of Orders[Unit Price] is then computed.  Note though this may or may not be the value of 'Unit Price' for the current row. It is more precise to say the foundset is all the rows in 'Orders' for which the values of column 1, column 2, ...column N match the respective values of the current row being computed.  ok?  

     

    #3 Filters automatically flow from the one side to the many side of a relationship.  if you put a calculated column in Product table =  SUM ( Sales[Line Margin] ), the result would be to sum all the 'Line Margin' values in the entire Sales table because the Filter context is still empty.  Do this:  CALCULATE ( SUM ( Sales[Line Margin] ) ), and again row is transitioned to filter context, applied to model, and values summed in Sales table is the now filtered foundset.  You don't need a RELATEDTABLE (which is is just a synonym for CALCULATETABLE anyway) because of automatic filter propagation from one -> many.  There is no automatic from many -> one unless you turn it "on" in the model (make relationships bi-directional - which imo should only be done after careful consideration).  

     

    #4 is explained in #2 above.  You need to understand how context transition works.  Row contexts are created in two ways.  For calculated columns, row context exists for each row the value is calculated.  In Measures, you can programatically create a row context using an iterator function like SUMX and the the other 'X' functions and others such as ADDCOLUMNS.   So for SUMX per your example, multiplication does happen first, then the summation of the values.  What Dax does first is evaluate which rows you are iterating over.  Which rows are aggregated is at the heart of what makes Dax work - manipulating the filter context under which the aggregation function is computed.

     

    Hope this makes sense...