MDX calculation with children and parents (contribution to total) - mdx

I got a cube with cadastral information of some neighborhoods of a city. One of the measures is 'cadastral value': the value of the land of a neighborhood.
Now, the city is divided into districts and a district, into neighborhoods (hierarchy with two levels).
The question is: I need to calculate the percentage that the value of each neighborhood represents compared with the parent (the district) and with the total (city), and also the same about the district compared with the city.
How can I do it?
I tried:
WITH MEMBER
[Measures].[Percentage] AS
([Nbh].[Nbh].[Nbh],[Measures].[Cad value].CurrentMember
/[Nbh].[Nbh].[Nbh],[Measures].[Cad value].CurrentMember.Parent)
SELECT
{[Measures].[Percentage]} ON 0,
[Nbh].[Nbh].[Nbh].AllMembers ON 1
FROM Cadastre
Where the dimensions are:
Nbh : Neighborhood
Cad value: Cadastral value
What I get is "error" in every result value, and the explanation is "Current member () : argument (0) type mismatch: expected:'level|hierarchy|dimension', got:'measure'"
What am I doing wrong?

WITH MEMBER [Measures].[Percentage] AS
([Nbh].[Nbh].[Nbh],[Measures].[Cad value].CurrentMember
/[Nbh].[Nbh].[Nbh],[Measures].[Cad value].CurrentMember.Parent)
There are two problems with this:
One, you are using a static set to compute the value of calculated member namely:
[Nbh].[Nbh].[Nbh]
This is NOT [Nbh].[Nbh].CURRENTMEMBER
Second and the bigger mistake: Using the currentmember on a measure. You can't do that. You can use Measures.CURRENTMEMBER but that's about it. It's best used on hierarchies which are used on axes.
That said, your approach is almost legit. You need to fetch the measure value for the parent.
This should work:
WITH MEMBER
[Measures].[Percentage] AS
DIVIDE
(
[Measures].[Cad value],
([Nbh].[Nbh].CURRENTMEMBER.PARENT,[Measures].[Cad value]) //Cad value for parent
)
SELECT
{[Measures].[Percentage]} ON 0,
[Nbh].[Nbh].[Nbh].AllMembers ON 1
FROM Cadastre

Try the following:
WITH MEMBER [Measures].[Parent %] AS
IIF(
[Nbh].[Nbh].CURRENTMEMBER IS [Nbh].[Nbh].[All]
,1
,[Measures].[Cad value] /
(
[Measures].[Cad value],
[Nbh].[Nbh].CurrentMember.Parent
)
), FORMAT_STRING = 'Percent'
SELECT
{[Measures].[Parent %]} ON 0,
[Nbh].[Nbh].[Nbh].AllMembers ON 1
FROM Cadastre;
Including the IIF is a defensive measure. If you switch to showing AllMembers of the complete hierarchy then the All member will be included. Here is an example using AdvWrks:
WITH
MEMBER [Measures].[Parent %] AS
IIF
(
[Product].[Subcategory].CurrentMember
IS
[Product].[Subcategory].[All Products]
,1
,
[Measures].[Internet Sales Amount]
/
(
[Measures].[Internet Sales Amount]
,[Product].[Subcategory].CurrentMember.Parent
)
)
,FORMAT_STRING = 'Percent'
SELECT
NON EMPTY
{[Measures].[Parent %]} ON 0
,NON EMPTY
[Product].[Subcategory].ALLMEMBERS ON 1
FROM [Adventure Works];
The above returns the following:
Without the IIF the expression is the following:
WITH
MEMBER [Measures].[Parent %] AS
[Measures].[Internet Sales Amount]
/
(
[Measures].[Internet Sales Amount]
,[Product].[Subcategory].CurrentMember.Parent
)
,FORMAT_STRING = 'Percent'
SELECT
NON EMPTY
{[Measures].[Parent %]} ON 0
,NON EMPTY
[Product].[Subcategory].ALLMEMBERS ON 1
FROM [Adventure Works];
We get the following because of lack of foresight:

The error is certainly because of this statement is incorrect:
WITH MEMBER
[Measures].[Percentage]
AS ([Nbh].[Nbh].[Nbh],[Measures].[Cad value].CurrentMember/[Nbh].[Nbh].[Nbh],[Measures].[Cad value].CurrentMember.Parent)
Try to make it like this
WITH MEMBER
[Measures].[Percentage]
AS ([Nbh].[Nbh].[Nbh],[Measures].[Cad value])/([Nbh].[Nbh].[Nbh],[Measures].[Cad value])

Related

calculate the cumulative % of a hierarchy member in icCube | TopPercent but than different

With the function TopPerent, you can get the set of members - ordered top down - that comply to the % value provided.
I would like to switch this function and get the cumulative % given the member.
Description of the image:
TopPercent in icCube, all countries in Excel ordered top down on Amount. Cum % caluclated. The BLUE highlighted values indicate the value I would like to obtain
I hope it will be enough to understand the point:
With
Set [OrderedCity] as
Order([Customer].[City].[City].Members,[Measures].[Internet Sales Amount],DESC)
Member [Measures].[Cum] as
Sum(
Head([OrderedCity],Rank([Customer].[City].CurrentMember,[OrderedCity])),
[Measures].[Internet Sales Amount]
)
Member [Measures].[Cum %] as
[Measures].[Cum] / ([Customer].[City].[All],[Measures].[Internet Sales Amount]),
Format_String = "Percent"
Select
Non Empty [OrderedCity] on 1,
{[Measures].[Internet Sales Amount],[Measures].[Cum],[Measures].[Cum %]} on 0
From [Adventure Works]

List all previous Years and measure till today such that all 12 Month data is available for year.Else exclude the year

We have a typical Date Dimension.
I am struggling to write an MDX to list the Dim.Year dimension member and measure contain data strictly for all month.(from Jan-Dec) otherwise exclude the year?.
This:
SELECT
[Measures].[Internet Sales Amount] ON 0
,[Date].[Calendar].[Calendar Year].MEMBERS ON 1
FROM [Adventure Works];
Returns this:
If I just now add in NON EMPTY I should get rid of 2009 and 2010:
SELECT
[Measures].[Internet Sales Amount] ON 0
,NON EMPTY
[Date].[Calendar].[Calendar Year].MEMBERS ON 1
FROM [Adventure Works];
Now returns:
The above is a very simple example.
Other scenarios might require us to get rid of nulls using other functions such as FILTER / NonEmpty / HAVING / IIF.
Edit
To just return years that have 12 months with data I've written the following (a wee bit more complicated than the above!). I will try to simplify later although you will definitely require an additional measure to achieve your goal,
WITH
MEMBER [Measures].[cntMths] AS
Count
(
NonEmpty
(
Descendants
(
[Date].[Calendar].CurrentMember
,[Date].[Calendar].[Month]
,SELF
)
,[Measures].[Internet Sales Amount]
)
)
SELECT
{
[Measures].[Internet Sales Amount]
} ON 0
,NON EMPTY
[Date].[Calendar].[Calendar Year].MEMBERS HAVING
[Measures].[cntMths] = 12 ON 1
FROM [Adventure Works];
Edit (for #sourav_agasti)
This is a solution against Adventure Works which only uses attribute hierarchies i.e. for a cube without a well formed Date dimension:
WITH
MEMBER [Measures].[cntMths] AS
Count
(
NonEmpty
(
[Date].[Calendar Year].CurrentMember
*
[Date].[Month of Year].[Month of Year].MEMBERS
,[Measures].[Internet Sales Amount]
)
)
SELECT
{} ON 0
,[Date].[Calendar Year].[Calendar Year].MEMBERS HAVING
[Measures].[cntMths] = 12 ON 1
FROM [Adventure Works];
This is the equivalent to Sourav's script using the above method:
WITH
MEMBER [Measures].[cntMths] AS
Count
(
NonEmpty
(
[Dim Year].[Year].CurrentMember
*
[Dim Month].[Month].MEMBERS
,[Measures].[Foo]
)
)
SELECT
{} ON 0
,[Dim Year].[Year].[Year].MEMBERS HAVING
[Measures].[cntMths] = 12 ON 1
FROM [Your Cube];
Further Edit
I chanced on an article last night which gives a more efficient method. Apparently Count - NonEmpty which I've done above is not tuned to work in block calculation mode whereas Sum -IIF is. So here is a quicker alternative using the later method:
WITH
MEMBER [Measures].[cntMths - S] AS
Sum
(
[Date].[Month of Year].[Month of Year].MEMBERS
,IIF
(
IsEmpty([Measures].[Internet Sales Amount])
,null
,1
)
)
SELECT
{[Measures].[cntMths - S]} ON 0
,[Date].[Calendar Year].[Calendar Year].MEMBERS HAVING
[Measures].[cntMths - S] = 12 ON 1
FROM [Adventure Works];
I took it as a challenge to write a code which gets you the result without there being any hierarchies anywhere. So here goes my attempt(after few hours of madness!).
You must be having a [Dim Month] dimension too. I am assuming the data there is stored like Dec-2014 or Dec 2014. Basically assuming that the last 4 digits give the year.
Now, one way you can figure out the years having data is to first list out all the months which don't have data and then figuring out the year for these months and then NOT displaying these years in the final output.
The below code does that for you:
WITH SET MonthsWithNoData AS
FILTER([Dim Month].[Month].CHILDREN, [Measures].[foo] = 0)
MEMBER [Measures].Year as
RIGHT([Dim Month].[Month].CURRENTMEMBER.member_value, 4)
SET SetOfYearsWithNoData AS
GENERATE(MonthsWithNoData, STRTOSET("[Dim Year].[Year].&[" + RIGHT(MonthsWithNoData.currentmember.member_value, 4) + "]"))
SET SetOfYearsWithData AS
([Dim Year].[Year].MEMBERS - SetOfYearsWithNoData)
member yearValues as
[Dim Year].[Year].currentmember.member_value
member wellFormedyearValues as
[Dim Year].[Year].currentmember.member_unique_name
SELECT {yearvalues, wellFormedyearValues} on 0,
SetOfYearsWithData on 1
from [Your cube]
I agree that the final output does not look too beautiful though. Having said that, a hierarchy would make the code much less complicated and the MDX would be much simpler. A [Calender] dimension with requisite hierarchies in place(as assumed in #whytheq's answer) would be the better approach in terms of elegance as well as performance.

MDX - Calculated Member with EXCEPT will not roll-up at all?

I have a Calculated Member were I want to aggregate a measure by YTD. I also want the measure to roll-up on all dimensions. There is one dimension value that I dont want to be part of the aggregation. The problem is when I try to filter this out the aggregation doesnt roll-up on the other dimensions.
This works and returns the correct value for all values in the [EK DIM OBJ KONTO] dimension, and rolls-up fine on all dimensions:
Aggregate
(
YTD([DATUM D].[Period].CurrentMember)
,[Measures].[UTFALL V]
)
When I try to add an EXCEPT-statement to exclude one value in the [EK DIM OBJ KONTO] dimension I get the wrong result. The Calculated Member always returns the same answer, it does not take any notice of the dimensions I am trying to slice it with.
Aggregate
(
{YTD([DATUM D].[Period].CurrentMember)}
*
{
Except
(
[EK DIM OBJ KONTO].[KTOB2 ID].[KTOB2 ID]
,[EK DIM OBJ KONTO].[KTOB2 ID].&[-]
)
}
,[Measures].[UTFALL V]
)
This is against the AdvWorks cube but seems to be working:
WITH
MEMBER [Measures].SumYtd AS
Aggregate
(
{YTD()}
,[Measures].[Internet Sales Amount]
)
MEMBER [Measures].SumException AS
Aggregate
(
{YTD()}
*
{
Except
(
[Customer].[Customer Geography].[Country].MEMBERS
,[Customer].[Customer Geography].[Country].&[United States]
)
}
,[Measures].[Internet Sales Amount]
)
SELECT
{
[Measures].[Internet Sales Amount]
,[Measures].SumException
,[Measures].SumYtd
} ON 0
,[Date].[Calendar].[Month].&[2007]&[11].Children ON 1
FROM [Adventure Works];

AverageOfChildren in MDX

One of the functions being used in a code sample is averageofchilren.
What exactly the AverageOfChildren aggregate function actually does?
How can we compare this with Avg() function in MDX ?
Maybe a custom measure is created in your cube.
Using AdventureWorks try this:
Script 1
SELECT
{[Measures].[Reseller Sales Amount]} ON 0,
NON EMPTY
{[Geography].[Geography].[Country].&[Australia].CHILDREN} ON 1
FROM [Adventure Works]
WHERE ([Date].[Calendar Year].&[2007])
That results in this:
Say I wanted to create a measure that returned the average reseller sales amount per region of each country then I could do the following:
Script 2
WITH
MEMBER [Measures].[AvgOfChildren] AS
AVG(
[Geography].[Geography].CURRENTMEMBER.CHILDREN,
[Measures].[Reseller Sales Amount]
)
SELECT
{ [Measures].[Reseller Sales Amount],
[Measures].[AvgOfChildren]
} ON 0,
{[Geography].[Geography].[Country].MEMBERS} ON 1
FROM [Adventure Works]
WHERE ([Date].[Calendar Year].&[2007])
You can see from the results for Australia (211,857.58) that the AverageOfChildren is the average of the numbers returned by script 1:

SSAS: Percent of Total not working in hierarchy

I have a simple olap cube - one set of measures and some unexciting dimensions.
I've add one calculation to get the "percent of total" sales against the gross sales measure. The code for this calculation is:
([Dim Stores].[Store Name].CurrentMember, [Measures].[Gross Sales])
/
([Dim Stores].[Store Name].Parent, [Measures].[Gross Sales])
This works.
Within the store dimension, there is a hierarchy called 'By State' where the stores are contained within.
Two questions please:
1. Any idea why the calculation would not work when I use the the 'By state' hierarchy i.e. the same calculation grouped by the next level up?
The state problem aside, any idea why my grand total shows an error even when I just use the Store Name?
TIA!
In poking around, I found a template within the "calculation tools" called "Percentage of Total". Using it, I translated my calculation to this:
Case
// Test to avoid division by zero.
When IsEmpty
(
[Measures].[Gross Sales]
)
Then Null
Else ( [Dim Stores].[By State].CurrentMember, [Measures].[Gross Sales] )
/
(
// The Root function returns the (All) value for the target dimension.
Root
(
[Dim Stores]
),
[Measures].[Gross Sales]
)
End
It worked!