Search code examples
ssasmdx

Account for tied ranks


I'm using the following:

WITH 
  SET [myset] AS 
    Order
    (
      {
          [Customer].[Country].[Country].MEMBERS
        * 
          [Customer].[Customer].[Customer].MEMBERS
      }
     ,[Measures].[Internet Sales Amount]
     ,ASC
    ) 
  MEMBER [Measures].[rank] AS 
    Rank
    (
      (
        [Customer].[Country].CurrentMember
       ,[Customer].[Customer].CurrentMember
      )
     ,[myset]
    ) 
  MEMBER [Measures].[newrank] AS 
    IIF
    (
        [myset].Item(
        [Measures].[rank] - 1).Item(0).Name
      <> 
        [myset].Item(
        [Measures].[rank] - 2).Item(0).Name
     ,1
     ,
      ([myset].Item([Measures].[rank] - 2),[Measures].[newrank]) + 1
    ) 
SELECT 
  {
    [Measures].[Internet Sales Amount]
   ,[Measures].[rank]
   ,[Measures].[newrank]
  } ON 0
 ,[myset] ON 1
FROM [Adventure Works];

It is the work of Amish Shah: http://blog.sqltechie.com/2010/03/rank-with-partitioning-mdx.html

Currently it does not give tuples that have the same value the same rank e.g. if x has an Internet Sales Amount of 10 and y also has 10, in the above they will not have the same rank.

Can the above be changed so that if they have the same value then they have the same value for [Measures].[rank] - and also the same value for [Measures].[newrank]?

(adding a third argument into the definition of [Measures].[rank] doesn't seem like a possible route to proceed as the Rank function then goes into cel-by-cell calculation mode)


Solution

  • How about using recursive calculated members like so -

    WITH 
      SET [myset] AS 
        Order
        (
          {
              [Customer].[Country].[Country].MEMBERS
            * 
              [Customer].[Customer].[Customer].MEMBERS
          }
         ,[Measures].[Internet Sales Amount]
         ,ASC
        ) 
      MEMBER [Measures].[myrank] AS 
        Rank
        (
          (
            [Customer].[Country].CurrentMember
           ,[Customer].[Customer].CurrentMember
          )
         ,[myset]
        ) 
    
    
    member prevmembervalue as 
    (myset.item(myRank - 2), [Measures].[Internet Sales Amount])
    
    member currentmembervalue as
    (myset.item(myRank - 1), [Measures].[Internet Sales Amount])
    
    MEMBER greaterthanprev as
    iif(currentmembervalue > prevmembervalue, 1, 0)
    
    member rankActual as
    iif
    (
     prevmembervalue = null, 1,
     iif(currentmembervalue > prevmembervalue,
      (myset.item(myRank - 2), rankActual) + 1,
      (myset.item(myRank - 2), rankActual)
     )
     )
    
    select myset on 1,
    {[Measures].[Internet Sales Amount], rankActual, myRank}
    on 0
    from 
    [Adventure Works]
    

    The measures greaterthanprev, currentmembervalue and prevmembervalue are actually not needed. Added them here just for some added clarification on the process.