MDX Query SUM PROD to do Weighted Average

2.3k views Asked by At

I'm building a cube in MS BIDS. I need to create a calculated measure that returns the weighted-average of the rank value weighted by the number of searches. I want this value to be calculated at any level, no matter what dimensions have been applied to break-down the data.

I am trying to do something like the following:

I have one measure called [Rank Search Product] which I want to apply at the lowest level possible and then sum all values of it

IIf([Measures].[Searches] IS NOT NULL, [Measures].[Rank] * [Measures].[Searches], NULL)

And then my weighted average measure uses this:

IIf([Measures].[Rank Search Product] IS NOT NULL AND SUM([Measures].[Searches]) <> 0,
SUM([Measures].[Rank Search Product]) / SUM([Measures].[Searches]), 
NULL)

I'm totally new to writing MDX queries and so this is all very confusing to me. The calculation should be

 ([Rank][0]*[Searches][0] + [Rank][1]*[Searches][1] + [Rank][2]*[Searches][2] ...)
 / SUM([searches])

I've also tried to follow what is explained in this link http://sqlblog.com/blogs/mosha/archive/2005/02/13/performance-of-aggregating-data-from-lower-levels-in-mdx.aspx

Currently loading my data into a pivot table in Excel is return #VALUE! for all calculations of my custom measures.

Please halp!

1

There are 1 answers

2
FrankPl On BEST ANSWER

First of all, you would need an intermediate measure, lets say Rank times Searches, in the cube. The most efficient way to implement this would be to calculate it when processing the measure group. You would extend your fact table by a column e. g. in a view or add a named calculation in the data source view. The SQL expression for this column would be something like Searches * Rank. In the cube definition, you would set the aggregation function of this measure to Sum and make it invisible. Then just define your weighted average as

[Measures].[Rank times Searches] / [Measures].[Searches]

or, to avoid irritating results for zero/null values of searches:

IIf([Measures].[Searches] <> 0, [Measures].[Rank times Searches] / [Measures].[Searches], NULL)

Since Analysis Services 2012 SP1, you can abbreviate the latter to

Divide([Measures].[Rank times Searches], [Measures].[Searches], NULL)

Then the MDX engine will apply everything automatically across all dimensions for you.

In the second expression, the <> 0 test includes a <> null test, as in numerical contexts, NULL is evaluated as zero by MDX - in contrast to SQL.

Finally, as I interpret the link you have in your question, you could leave your measure Rank times Searches on SQL/Data Source View level to be anything, maybe just 0 or null, and would then add the following to your calculation script:

({[Measures].[Rank times Searches]}, Leaves()) = [Measures].[Rank] * [Measures].[Searches];

From my point of view, this solution is not as clear as to directly calculate the value as described above. I would also think it could be slower, at least if you use aggregations for some partitions in your cube.