In many organizations like the financial and health sector, knowing a average (mean) number isn’t enough. They also want to know a ranking of the salespeople, patients or products with their percentile. In other words, how does your Germany branch stack up to its peer branches? The result, I’d be after is something like the following in Analysis Services:
The code that is covered here has been broken into many steps that could easily be done in a single few steps. I’m doing this to show the code incrementally and could easily be altered to your liking. To let’s begin!
First, we must create an ordered set that we can later use to rank the dataset on. I’m ordering the data based on the sales amount where my tuple is based on Subcategory. I’m also filtering the data to where we have sales. This step is optional but will come into play in this example later.
WITH SET [SalesRankSet] ASFILTER(ORDER([Product].[Subcategory].CHILDREN , [Measures].[Internet Sales Amount],BDESC), [Measures].[Internet Sales Amount] > 0)
The next step is create a rank measure which ranks our set that we just created from 1 to N. This is done through the RANK function while passing in the set shown below:
MEMBER [Measures].[SalesRank] AS RANK([Product].[SubCategory].CurrentMember, [SalesRankSet])
The next measure is the count of how many subcategories you have. You’ll use this later in the formula. One step that bit me over and over again was making sure that you only count where there’s a cross-join between subcategories and where you had sales. If you don’t do this, you’ll come back with the count of all subcategories (38) and you should get back the answer of 18 for your percentile. Use the COUNT function with a NONEMPTY clause to accomplish this as shown here:
MEMBER [Measures].[Count] as COUNT(NONEMPTY([Product].[SubCategory].Members,[Measures].[Internet Sales Amount]))
The last prep work you’ll have is to do the actual percentile formula.That formula is 1 - Ranking / Count of Members. To translate that into MDX that we can use the simple MDX below now that we’ve built all the individual calculations and set above.
Member [Measures].[Percentile] as 1-[Measures].[SalesRank]/[Measures].[Count],FORMAT_STRING = 'Percent'
Lastly, just select the data out of the set and calculations using familiar MDX code:
SELECT {[Measures].[SalesRank],[Measures].[Percentile], [Measures].[Internet Sales Amount]} on Columns, [SalesRankSet] on RowsFROM [Adventure Works]
Here’s the complete code that works against the AdventureWorks sample cube:
WITH SET [SalesRankSet] ASFILTER(ORDER([Product].[Subcategory].CHILDREN , [Measures].[Internet Sales Amount],BDESC), [Measures].[Internet Sales Amount] > 0)MEMBER [Measures].[SalesRank] AS RANK([Product].[SubCategory].CurrentMember, [SalesRankSet])MEMBER [Measures].[Count] as COUNT(NONEMPTY([Product].[SubCategory].Members,[Measures].[Internet Sales Amount])) Member [Measures].[Percentile] as 1-[Measures].[SalesRank]/[Measures].[Count],FORMAT_STRING = 'Percent'SELECT {[Measures].[SalesRank],[Measures].[Percentile], [Measures].[Internet Sales Amount]} on Columns,
[SalesRankSet] on RowsFROM [Adventure Works]