This post explains how you can create a ranking of data from an OLAP MDX query. This will take the results from the query, and assign a ranking to each row. i.e. 1st, 2nd, 3rd best rows etc.
The first thing to do is to decide two things.
1) What measure do you want to rank by
2) What data set are you returning
Let’s assume we want to rank all stores by sales value. The basic non-ranked MDX query would be something like this
SELECT
{[Measures].[Sales Value]} ON 0,
{[Store].[Store Name].members} ON 1
FROM
[SalesCube]
So our measure is Sales Value, and our data set (granularity) is Store Name. We now want to create an ordered set of this data, ordered by Sales Value. We do this with the ORDER() function, which takes a set, a measure and either ascending or descending as its parameters. Note that by specifying the attribute twice we remove the [All] member from the set.
WITH SET [OrderedSet] AS
ORDER([Store].[Store Name].[Store Name].MEMBERS,
[Measures].[Sales Value],
BDESC)
SELECT
{[Measures].[Sales Value]} ON 0,
{[OrderedSet]} ON 1
FROM
[SalesCube]
The next stage is to apply a ranking to this ordered set. Helpfully, MDX provides us with a Rank() function, which takes a member and a set as its parameters. All it does is locate the member within the set and return its position. Because we have ordered the set, it will give us the ranking.
WITH SET [OrderedSet] AS
ORDER([Store].[Store Name].[Store Name].MEMBERS,
[Measures].[Sales Value],
BDESC)
MEMBER [Measures].[Rank] AS
RANK([Store].[Store Name].CurrentMember,
[OrderedSet])
SELECT
{[Measures].[Rank], [Measures].[Sales Value]} ON 0,
{[OrderedSet]} ON 1
FROM
[SalesCube]
You can now easily expand this to only show you the top x records, by using the Head() function on the ordered set. In this example we’re only showing the top 10. You could also use Tail() to find the bottom x records. Other functions you can use include TopPercent(), TopSum(), BottomPercent() and BottomSum().
WITH SET [OrderedSet] AS
ORDER([Store].[Store Name].[Store Name].MEMBERS,
[Measures].[Sales Value],
BDESC)
MEMBER [Measures].[Rank] AS
RANK([Store].[Store Name].CurrentMember,
[OrderedSet])
SELECT
{[Measures].[Rank], [Measures].[Sales Value]} ON 0,
{HEAD([OrderedSet], 10)} ON 1
FROM
[SalesCube]
Trackback. Link to this post was added to our site in the [SSAS Articles]/[MDX] section:
http://www.ssas-info.com/analysis-services-articles/50-mdx/878-ranking-results-from-mdx-queries
Dear Alex,
Write more fantastic posts as usually!!
cheers!!
Pedro
Hi Pedro, thanks for stopping by.
Sorry about the lack of activity here at the moment – blame my pesky customers 🙂 too much work to do!
I’ll try and get another frog-blog-top-tip up here soon!
Alex
I always read your blog in high spirits. Thanks 🙂
hi,
i’m trying to find out the Top10 products on retailers
WITH SET [OrderedSet] AS
ORDER ( [Retailer].[Retailer Name].[Retailer Name].MEMBERS,
[Measures].[Sales Value Gross RRP Excluding Taxin Local Currency] ,
BDESC)
MEMBER [Measures].[Rank] AS
RANK([Retailer].[Retailer Name].CurrentMember,
[OrderedSet])
SELECT
{[Measures].[Rank], [Measures].[Sales Value Gross RRP Excluding Taxin Local Currency]} ON 0,
{HEAD([OrderedSet], 10)} ON 1
FROM
[CubeClientAdmin]
it gives the error:
Error 1 MdxScript(CubeClientAdmin) (69, 1) Parser: The syntax for ‘WITH’ is incorrect. 0 0
and i couldn’t trace out the error in ‘with’,
can you tell me what is the error in the above code?
Thanks,
Regards
Viji
Hi Viji
Syntactically, I can’t find anything wrong with your query. What database are you running it against? And what query tool are you using?
My example was using SQL 2005, querying using Management Studio.
Alex
Hi Alex,
thanks for your reply. I’m using SQL 2005 and i queried using analysis services.
Regards,
Viji
Hi Viji
What happens when you run it as a query using SQL Server Management Studio?
Alex
what about ties? Your use of the ‘order’ method does not account for ties correctly.
Hi Gene
Very good point. However you can get around this by nesting multiple ORDER statements.
ORDER(ORDER(xxx,xxx,xxx),xxx,xxx)
The Outer statement will be the primary order, the second one in willl be the decidor if there are duplicate primary sort values causing a tie.
Thanks for stopping by!
Alex
Thanks, your example of the rank function is very clear. I was having trouble with someone else’s explanation.
Thanks a lot Alex.. even after so long time you can still see how many of us make use of this valuable piece of code. Its so simple and very clear… Thanx again.
I’ve been looking for that for so long! Thanks a lot for for this great explanation…a appreciate it!!