Forum Discussion

dhrubojtg's avatar
dhrubojtg
Frequent Visitor
5 years ago
Solved

Calculate multi column arguments with vs without Filter -understanding internal logic

Dear Dax Gurus I am learning Dax and need your expert guidance PBIX reference1: https://www.dropbox.com/s/6v789rra5rerowo/Contoso.pbix?dl=0  Result screenshot of comparison of both measures...
  • AntrikshSharma's avatar
    5 years ago

    dhrubojtg  a lot of things in DAX are syntax sugars. So taking the example of 2nd code:

    This:

     

    CalculateWithoutFilter =
    CALCULATE (
        [Sales Amount],
        Products[Brand Name] = "Contoso",
        Customers[Country] = "Canada"
            || Customers[Country] = "China",
        'Calendar'[Is Work Day] = "WorkDay",
        'Calendar'[Calendar Month] = 200701
    )
    

     

    Exands internally and becomes:

     

    CalculateWithoutFilter =
    CALCULATE (
        [Sales Amount],
        FILTER ( ALL ( Products[Brand Name] ), Products[Brand Name] = "Contoso" ),
        FILTER (
            ALL ( Customers[Country] ),
            Customers[Country] = "Canada"
                || Customers[Country] = "China"
        ),
        FILTER ( ALL ( 'Calendar'[Is Work Day] ), 'Calendar'[Is Work Day] = "WorkDay" ),
        FILTER (
            ALL ( 'Calendar'[Calendar Month] ),
            'Calendar'[Calendar Month] = 200701
        )
    )
    

     

    The expansion is clearly visible in the Logical query plan that Formula Engine generates (There are 2 engines in DAX, Storage and Formula Engine):

    I also have the Contoso Model so here is how the expansion appers in the query plan generated internally by DAX engine: (If you want to know how to read a query plan check the first link after my signature)

    So how is that both codes are different?

     

    The difference is in the way you have referenced Products, Calendar, and Customer tables inside FILTER, when the expansion in previous code happened it became FILTER ( ALL ... which ignores any existing filter on the column/table, but you are writing naked table reference which is getting filtered in the filter context so here is what happens in the with Filter version i.e. FILTER ( Products:

     

    1.  There is an outer filter context outside CALCULATE where you have called the measure

    2. CALCULATE evaluates the Products table in the outer filter context and once this table is filtered, FILTER evaluates the conditions that you have specified, i.e. Brand = "Contoso"

    3. CALCULATE applies this new filter of Brand = Contoso to the filter context in which it evaluates the sales amount

     

    The problem in the above execution is once the products table is filtered in a filter context where Brand is "Fabrikam", the result of FILTER will be an empty table

     

    Here is what happens when you use without FILTER version, i.e. Products[Brand Name] = "Contoso"

     

    1.  There is an outer filter context outside CALCULATE where you have called the measure

    2.  Products[Brand Name] = "Contoso" expands and becomes FILTER ( ALL ( Products[Brand Name] ), Products[Brand Name] = "Contoso" ), the ALL ignores any existing filter context on the same column and always returns all the brands and in this case the result of CALCULATE won't be an empty table and Contoso will be the final filter context for each row of your visual

    3. CALCULATE overrides the exisiting filters on Brand column with new filter which is Contoso and evaluates each cell of your visual where the filter context for Brand is Contoso

     

    Now if the result of CalculateWithFilter is what you want then you need to use KEEPFILTERS like this:

     

    CalculateWithoutFilter =
    CALCULATE (
        [Sales Amount],
        KEEPFILTERS ( Products[Brand Name] = "Contoso" ),
        KEEPFILTERS ( Customers[Country] = "Canada" || Customers[Country] = "China" ),
        KEEPFILTERS ( 'Calendar'[Is Work Day] = "WorkDay" ),
        KEEPFILTERS ( 'Calendar'[Calendar Month] = 200701 )
    )
    

     

     KEEPFILTERS does a SET operations where it simply intersects outer filter and the new filter created by CALCULATE if the values in the outer filter exists in new one then you will get a result otherwise a blank.

     

    Also read this:

    https://forum.enterprisedna.co/t/thinking-behind-use-of-keepfilters/10556/2

  • dhrubojtg's avatar
    5 years ago

    It is the expanded version you shared which I expect to give same result as the non expanded form , but when I apply it doesnot

     

    CalculateWithoutFilterAllExp =
    CALCULATE (
        [Sales Amount],
        FILTER ( ALL ( Products[Brand Name] ), Products[Brand Name] = "Contoso" ),
        FILTER (
            ALL ( Customers[Country] ),
            Customers[Country] = "Canada"
                || Customers[Country] = "China"
        ),
        FILTER ( ALL ( 'Calendar'[Is Work Day] ), 'Calendar'[Is Work Day] = "WorkDay" ),
        FILTER (
            ALL ( 'Calendar'[Calendar Month] ),
            'Calendar'[Calendar Month] = 200701
        )
    )