This week I got an email from a reader named Brad asking a specific question regarding MDX. Here is his question:
I need an MDX query to return me the top 5 values and then default all others to an “other” group and ranks based on the resulting measure value. For instance, if we are talking about a measure by month for a full year, I need the output to look like this:
Dim Measure Rank
Nov $500 1
Mar $400 2
Feb $300 3
Jan $200 4
Dec $100 5
Other $350 6Any input will be most appreciated!
Thanks,
Brad
I thought this was a good question which is why I thought I’d take the time to blog this out. In this example I’ll be using the Adventure Works cube and the Adventure Works Customer dimension.
The first step is to determine what are our Top 5 Customers. To do this, we can use a simple TopCount function to build a set of the Top 5 Customers.
with dynamic set [Top 5 Customers] as
Topcount(
[Customer].[Customer].[Customer].members,
5,
[Measures].[Internet Sales Amount]
)
Once we have our Top 5 Customers, then we can easily determine everyone else. To create our custom “Others” group, we need to create a Calculated Member (Custom Member). To create the Calculated Member, you need to specify the dimension, attribute hierarchy, and member name for your custom member (ie [Customer].[Customer].[Others]).
member [Customer].[Customer].[Others] as
Aggregate(
Except(
[Customer].[Customer].[Customer].members,
[Top 5 Customers]
)
)
To create our Others custom member, we need to use the Except function to basically specify that we want our custom member to include all our customers except the Top 5 Customers set we previously created. Also, don’t forget to wrap the set in the Aggregate function.
Lastly, we create our set that will actually be used in our query. This set will include our first set containing our Top 5 Customers as well as our Others custom member. We can use the Top 5 Customers set with our custom member because all members in the set are from the same Customers hierarchy.
dynamic set [Top 5 & Others] as
{
[Top 5 Customers],
[Customer].[Customer].[Others]
}
with dynamic set [Top 5 Customers] as
Topcount(
[Customer].[Customer].[Customer].members,
5,
[Measures].[Internet Sales Amount]
)
member [Customer].[Customer].[Others] as
Aggregate(
Except(
[Customer].[Customer].[Customer].members,
[Top 5 Customers]
)
)
dynamic set [Top 5 & Others] as
{
[Top 5 Customers],
[Customer].[Customer].[Others]
}
Select [Measures].[Internet Sales Amount] on 0,
[Top 5 & Others] on 1
From [Adventure Works]
I hope that was pretty straight forward and not too confusing. If you thought this was helpful leave me a comment and let me know! And if you have any questions or comments, feel free to leave a comment.
Thanks again, Brad, for the great question!
Check out my next blog post to see how to return the numeric rank of the customers!
Hi Ryan,
Please provide the query to give ranks to the result
Hi, that’s a good question. I thought I’d post a blog on the Rank function to answer this question. You can find it here: http://sqldusty.com/2014/08/18/the-mdx-rank-function/
Thanks
Great post – a couple of questions – in the MDX I have been writing so far I have been saying “WITH SET [X] AS…” . I’ve never used the keyword “DYNAMIC”. Does this word make a difference?
The second question is a little more involved – if I want to generate this set against another set, say our top 5 countries, how would the syntax change? So it would be the Top 5 customers plus ‘others’, for each of a set of 5 countries? Do we need the Generate function?