Handling SSRS Multi-Valued Parameters in DAX Queries

Last year I blogged about using DAX queries inside SSRS reports but one topic I didn’t touch on was how to handle parameters. Marco wrote a post on using parameters in DAX earlier this year but didn’t cover how to handle multi-valued parameters in SSRS, so I thought I’d write a post to fill that gap.

Let’s start by assuming you’ve built a simple SSAS 2012 Tabular model that contains the DimDate table from Adventure Works, that you want to build an SSRS report that shows data from that table and you want to parameterise that report by the values in the EnglishDayNameOfWeek column, ie by day.

If you were writing the query from scratch, probably the best way of doing it would be to use the CalculateTable() function like so:

evaluate
calculatetable(
DimDate
, DimDate[EnglishDayNameOfWeek] = "Monday"
)

This query returns the whole of the DimDate table filtered where EnglishDayNameOfWeek is Monday.

image

To filter by Monday or Tuesday, you’d need to do something like this:

evaluate
calculatetable(
DimDate
, DimDate[EnglishDayNameOfWeek] = "Monday"
|| DimDate[EnglishDayNameOfWeek] = "Tuesday"
)

Since there is no way of doing an IN in DAX, you might be able to guess what the big problem that needs to solved when handling multi-value parameters in DAX is: with this style of query, for each parameter value that is selected you need to add a new OR condition and the only way of doing that is to generate the query dynamically. While that’s perfectly possible in SSRS it’s something you may want to avoid because it makes report development awkward.

As an alternative to dynamic query generation you can make use of the DAX PathContains() function. Although it’s intended for use when flattening out parent/child hierarchies, it’s useful here because it allows you to see whether a particular string value appears in a pipe-delimited list. You can use it with the Filter() function to get all the Mondays and Tuesdays like so:

evaluate
filter(
DimDate
, pathcontains("Monday|Tuesday", DimDate[EnglishDayNameOfWeek])
)

There’s a problem with using it this way, unfortunately – it’s not very efficient. Looking in Profiler at the Vertipaq SE Query Begin/End events, you can see that Storage Engine has to call back to the Formula Engine to use the PathContains() function when filtering:

image

…and as Jeffrey Wang describes here, this can be very expensive indeed. However, its impact can be lessened if you have a small number of potential parameter values by doing this instead:

evaluate
calculatetable(
DimDate
, filter(
values(DimDate[EnglishDayNameOfWeek])
, pathcontains("Monday|Tuesday", DimDate[EnglishDayNameOfWeek])
)
)

Here, I’m only filtering the table of distinct values in the EnglishDayNameOfWeek column (which has only got 7 rows), and then taking that table and using it as a filter with the calculatetable() function on the main DimDate table. In this case there’s still a callback but only on a filter on a relatively small table, and the filter on the larger table, DimDate, is performed in the most efficient way possible.

How, then, can you take this query pattern and use in in your SSRS report? The first thing to do is to create a dataset that returns all the days of the week, using the following query:

evaluate values(DimDate[EnglishDayNameOfWeek])

image

This, then, can be used to provide the available values for an SSRS multi-valued parameter. This should all be straightforward for anyone who has used SSRS before.

image

image

You can then add a new query parameter to our main dataset, the one that queries the DimDate table:

image 

The next problem to solve is the fact that when using the Analysis Services connection type in SSRS, when you have a multi-valued parameter SSRS assumes you’re using MDX to query a cube. Therefore, if you have selected Monday and Tuesday in your parameter, SSRS will pass a string containing an MDX set expression like the one below through to the query parameter:

{ Monday,Tuesday }

You therefore need to do some string manipulation to turn this into a pipe-delimited string of the type that PathContains() can use. Here’s the complete DAX query that shows how this can be done:

evaluate
calculatetable(
DimDate
, filter(
values(DimDate[EnglishDayNameOfWeek])
, pathcontains(
substitute(
substitute(
substitute(
@DayNames
, "{ ", "")
, " }", "")
, ",", "|")
, DimDate[EnglishDayNameOfWeek])
)
)

It’s pretty simple: I’m using Substitute() to remove the opening and closing braces, and to turn the commas into pipes.  With that done, you now have an SSRS report using a DAX query that can handle multi-valued parameters!

image

36 thoughts on “Handling SSRS Multi-Valued Parameters in DAX Queries

  1. Hey Chris,

    have you thought of using FIND instead of PATHCONTAINS?
    doing so makes it unnecessary to use SUBSTITUTE to replace characters that are added by SSRS automatically and you can use the parameter directly:

    EVALUATE
    CALCULATETABLE(
    DimDate,
    FILTER(
    VALUES(DimDate[EnglishDayNameOfWeek]),
    FIND(DimDate[EnglishDayNameOfWeek], “{Monday,Tuesday}”, , -1)>0
    )
    )

    for some reason you have to specify the 3rd and 4th parameter of the FIND function otherwise you get an error eventhough those parameters are optional

    I have not checked the performance yet but I’d assume that both approaches perform similar

    Gerhard

    1. Yes, that’s an option but it’s less robust I suppose: what happens when you have one parameter value that appears as part of another parameter value, for example “web” and “Webb”?

    1. Hi Chris,

      I was able to get the same result without using the FILTER function inside Calculatetable. I used this query:

      evaluate
      calculatetable(
      DimDate
      , pathcontains(
      substitute(
      substitute(
      substitute(
      @DayNames
      , “{ “, “”)
      , ” }”, “”)
      , “,”, “|”)
      , DimDate[EnglishDayNameOfWeek])
      )

      Both approaches have same result and response time.

      Ayad

  2. Hello Chris, been reading about your posts for SSRS and DAX and I can’t thank you enough. They have helped me sooo much in one of our projects.

    I have a question, referring to your example mentioned above, is there a way to include a member “All” that would basically get all the values for the Weekdays (Like we have in MDX).

  3. Hello Chris, I implemented the multi value parameter as you mentioned in the blog and my reports are now running as expected. However I’m trying to implement an additional feature and wanted to see if you came across something like that before.

    If a user selects the (All) member in the filter I am trying to find a way of not having to pass all the possible values in a string to improve the performance, I was thinking of using this formula as one of the arguments in my calculatetable function but i guess it’s not allowed by DAX

    Any idea if this can be done?

    EVALUATE(

    SUMMARIZE(
    CALCULATETABLE(‘Loyalty Transactions’,
    CALCULATETABLE(‘Date’,DATESBETWEEN(‘Date'[ActualDate],”01/01/2013″,”01/31/2013″)),
    IF(@Param = “All”,FILTER(VALUES(‘Loyalty Entry Type'[Type]),’Loyalty Entry Type’),,pathcontains(substitute( substitute( substitute( @LoyaltyTransactionTypeType , “{ “, “”) , ” }”, “”) , “,”, “|”),’Loyalty Entry Type'[Type])))),
    [TransactionNo],
    ‘Date'[ActualDate])

    The idea here is that if the user selected ALL then I’m using a filter that basically selects all values instead of having to go through the pathcontains function.

      1. Yeah that seems to be the issue, IF doesn’t accept returning tables or DAX doesn’t accept the IF as a possible type for Tables.

        I was trying to improve the performance of my query as one of my filters contains around 150 Items and if the user decides to check All performance goes down a little

      2. Just wanted to share a little finding, I found that removing the Substitute function in DAX and handling it in SSRS with Replace improved performance for reports that have large number of filters/parameters.

      3. Thanks Omar, that makes sense. In fact, you could probably get much better performance by dynamically generating the DAX query using SSRS expressions, instead of writing the kind of complex DAX I use here.

      4. I’m actually looking into generating the Query dynamically to only apply the filter when All is not selected.

        Do you have any posts regarding dynamic DAX queries in SSRS?

      5. Thanks anyways 🙂

        Yeah it shouldn’t be a problem I was just wondering if you had any special posts about it, your posts usually cover stuff I haven’t seen before

  4. Hi Chris,

    Thanks for all your blog posts! they’re incredibly helpful.
    I have one question about regarding the parameter usage in this though, why is it that you’re using the @ symbol for the parameters instead of using string concatenation?

    Would that work the same way using string concatenation?

    Thanks!

    1. The @ denotes a parameter – both DAX and MDX support parameters. They’re much easier to work with than using string concatenation.

  5. Hi Chris,

    I would like to do something quite similar: pass a multivalue parameter in a SSAS Tabular Action (type Rowset). How can you pass a list of products for example to filter your rowset ?
    I manage to pass a single value filter but not a multi value….

    Regards

  6. Hi Guys,

    One option is to use the JOIN function to generate a delimited list from a multi-valued parameter.

    Expression: =Join(Parameters!Days.Value, “|”)

    DAX query:
    EVALUEATE
    CALCULATETABLE(
    ‘Order Date’,
    FILTER(
    VALUES(‘Order Date'[EnglishDayNameOfWeek])
    , PathContains(@Days, ‘Order Date'[EnglishDayNameOfWeek]
    )
    )
    )

    Cheers,
    Ivan

  7. This was posted a while back, and I have found this extremely helpful. However, I am having the following issue:
    When I select 2 variables, the result set comes back empty.
    When I select 1 or 3 or more variables, the result set returns correct data.

    I have two parameters setup against this report using the PathContains pattern. They both have this issue. They work with any selection less than or greater than 2. Is this a common issue that anyone else has experienced/ resolved?

    FILTER (
    Calendar,
    Calendar[YEAR] = value(@YearParam)
    && Calendar[MONTH] = value(@MonthParam)
    && PATHCONTAINS (
    SUBSTITUTE (
    SUBSTITUTE ( SUBSTITUTE ( @WeekParam, “,”, “|” ), “{“, “” ),
    “}”,
    “”
    ),
    Calendar[WEEK]
    )
    ),
    FILTER (
    DivCode,
    PATHCONTAINS (
    SUBSTITUTE (
    SUBSTITUTE ( SUBSTITUTE (@DivParam, “,”, “|” ), “{“, “” ),
    “}”,
    “”
    ),
    DivCode[DIV_CODE]
    )

    Thanks
    -Brian

  8. I resolved the issue by following Ivan’s recommendation:
    I removed all substitute functions from the DAX, and wrote the Paramater to be an expression with Replace().

    Now the query works as expected. I am not sure why there was an issue with the DAX Substitute() version.

  9. Hi,

    Can you please help me to add the “ALL” parameter in the SSRS report.

    evaluate
    (
    calculatetable
    (
    summarize
    (
    ‘R_Clndr’,
    ‘R_Clndr'[Year_WW]
    ),
    pathcontains(@fltr_Month,’R_Clndr'[Month])
    )
    )
    order by ‘R_Clndr'[Year_WW]

    The result is below:
    R_Clndr[Year_WW]
    201606
    201607
    201608
    201609
    201610

    I need the result below.

    R_Clndr[Year_WW]
    ALL
    201606
    201607
    201608
    201609
    201610

    Can you please help me asap.

    regards,
    Reddeppa

  10. I have SSRS report with DAX query multivalued Parameter, CalendarYear, if I select Multiple Years then run the report, it is throwing an error, your help will be much appreciated

    my query in SSRS report

    EVALUATE
    CALCULATETABLE(
    SUMMARIZE(FactInternetSales
    ,’DimProductCategory'[EnglishProductCategoryName]
    ,’DimProduct'[EnglishProductName]
    ,’DimProductSubcategory'[EnglishProductSubcategoryName]
    ,DimDate[CalendarYear]
    ,”Total Sales Amount”,SUM(FactInternetSales[SalesAmount])
    ,”Order Quantity”, SUM(‘FactInternetSales'[OrderQuantity])
    ),PATHCONTAINS(@Year,DimDate[CalendarYear])
    )

  11. I am able to resolve the issue with multivalued parameter in SSRS, we have split the values into multiple rows using SUBSTITUTE and PATHCONTAINS function.

    EVALUATE
    CALCULATETABLE(
    SUMMARIZE(FactInternetSales
    ,’DimProductCategory'[EnglishProductCategoryName]
    ,’DimProduct'[EnglishProductName]
    ,’DimProductSubcategory'[EnglishProductSubcategoryName]
    ,DimDate[CalendarYear]
    ,”Total Sales Amount”,SUM(FactInternetSales[SalesAmount])
    ,”Order Quantity”, SUM(‘FactInternetSales'[OrderQuantity])
    ),PATHCONTAINS(
    SUBSTITUTE(
    SUBSTITUTE(
    SUBSTITUTE(
    @Year
    , “{ “, “”)
    , “}”, “”)
    , “,”, “|”)
    , DimDate[CalendarYear])
    )

    Thank you
    Vishwanath

Leave a Reply to IvanCancel reply