MDX different expressions, same result - ssas

The following two statements return the same results in the cube, is one more optimized than the other or is there some compiler magic happening in the background?
CREATE MEMBER
CURRENTCUBE.[Measures].[Total Interest Expense]
AS
AGGREGATE(
EXISTING({([GL Income Statement Account].[Account Type].&[INTEREST EXPENSE])}),
[Measures].[Amount]
)
CREATE MEMBER
CURRENTCUBE.[Measures].[Total Interest Expense]
AS
(
[GL Income Statement Account].[Account Type].&[INTEREST EXPENSE],
[Measures].[Amount]
)

These are actually pretty much the same expressions. In the first expression, the Measures.[Amount] is aggregated over the set [GL Income Statement Account].[Account Type].&[INTEREST EXPENSE](which is actually a member). The EXISTING clause does not have any significance as you are making the set(first parameter to the AGGREGATE function) context independent by defining it as a member. In the second expression, the value of the measure is evaluated over the set(which) is again just a member. (Tuples comprising a measure are actually numeric in nature).

Related

MDX Scope to get denominator

I have a SSAS multidimensional cube and i am trying to calculate a denominator for a query by using a scope statement.
I am trying to assign the measure "Total SalesCumulative" the total value of all the sales for all the stores. I want this to stay being the total value and not get sliced when in a pivot table. The measure called Total Sales sums up all the sales for each store. I have gotten as far as the below but this just returns the value for each store and shows the same value as Total Sales.
SCOPE ([Measures].[Total SalesCumulative],[Dim Store].[Store Name].members);
THIS = ([Dim Store].[Store Name].[All],[Measures].[Total Sales]);
END SCOPE;
Has anyone got any suggestions how I can amend this?
I have checked your formula on Adventure Works database, and it seems correct. Just to be sure, you can check what you get with the query like the one below in SSMS (without making scope assignment):
with member measures.[All Order Count] as
([Measures].[Internet Order Count],[Product].[Model Name].[All Products] )
select {[Measures].[Internet Order Count] ,measures.[All Order Count] } on 0,
[Product].[Model Name].members on 1
from [Adventure Works]
Have you tried to clear cash before running the query after you made the change?
Secondly, maybe there is some other scope assignment in the script, that affects the same measure and dimension and overrides your formula, because the last scope assignment wins.
Try to add FREEZE(THIS) to your scope statement just to check if it will change the numbers:
SCOPE ([Measures].[Internet Order Count],[Product].[Model Name].members);
THIS = ([Product].[Model Name].[All Products] , [Measures].[Internet Order Count]) ;
FREEZE(THIS);
END SCOPE;

CURRENTMEMBER function gives an error in MDX

I have my dimension as below:
I want to get one market at a time.
When I use this query, I am getting the list of all the members as I am using .MEMBERS function:
SELECT [MARKET BASE].[Market Base].[Market Base].MEMBERS ON 1,
[Measures].[% OTC Sales] ON 0
FROM [PharmaTrend Monthly Ext];
But when I use the following query to get only the current member then I get an error saying: The CURRENTMEMBER function expects a hierarchy expression for the 1 argument. A member expression was used.
SELECT [MARKET BASE].[Market Base].[Market Base].CURRENTMEMBER ON 1,
[Measures].[% OTC Sales] ON 0
FROM [PharmaTrend Monthly Ext];
UPDATE:
When I use the below query, I get the result with All member:
WITH
MEMBER [Market] AS
[MARKET BASE].[Market Base].[Market Base].CURRENTMEMBER
SELECT [Measures].[% OTC Sales] ON 0,
[Market] ON 1
FROM [PharmaTrend Monthly Ext];
How can I go about resolving this?
CURRENTMEMBER is implicitly picked if you have any member from the hierarchy in scope and laid out on axis. By default it is the ALL member.
WITH MEMBER [Measures].[Market] AS
[MARKET BASE].[Market Base].CURRENTMEMBER.NAME
SELECT [MARKET BASE].[Market Base].[Market Base].MEMBERS ON 1,
{[Measures].[% OTC Sales], [Measures].[Market]} ON 0
FROM [PharmaTrend Monthly Ext];
This will return the name of the current market selected or on axis(in scope).
Just to be precise chaps - currentmember does not iterate over anything in mdx. None of the mdx I see in the original post is using any sort of iteration.
This function is as close as you get to a loop in mdx:
GENERATE
Also Filter can be thought of as an iterator.
CURRENTMEMBER is generally used in a WITH clause for claculations. What it does is pick up the current member for each member that is in context - this basically means what you see in the result table.

What does MDX Aggregate() do with a single argument?

I understand how to use the MDX Aggregate() and Sum() functions, and the differences between them.
(One interesting one is that the Sum of a measure defined at a higher level in a hierarchy over that level's Children multiplies the measure by the number of children - whereas Aggregate "correctly" returns just the value defined at the higher level).
The documented syntax on MSDN is:
Aggregate(Set_Expression [ ,Numeric_Expression ])
I've always used it with both arguments. But what does Aggregate do when only the set_expression argument is provided? The documentation (again from MSDN) is pretty obscure:
If a numeric expression is not provided, this function aggregates each measure within the current query context by using the default aggregation operator that is specified for each measure.
I tried it in an MDX query like this:
WITH MEMBER WeekSummedTotal AS
Aggregate([Days].[WeeksAndDays].CurrentMember.Children)
SELECT
{Measures.ThingoCount,Measures.WeekTotal,Measures.WeekSummedTotal} ON 0,
[Days].[WeeksAndDays].[WeekName] ON 1
FROM DateGRoupingTest
What would this do? Would Aggregate aggregate the cube's default measure over the set? Or the set Measures.Members? Or the set of other measures specified on the 0 axis?
None of these! The query runs and returns results, but the calcd measure WeekSumTotal shows #Error, with a completely nonsensical error:
Aggregate functions cannot be used on calculated members in the measures dimension
Now this is true, but completely irrelevant. None of the other measures in the query is calculated, and in fact the cube doesn't have any calculated members. So what is Aggregate() actually trying to do here? Is this error message (again, in MDX!) completely misleading?
ADDITION: #whytheq in the answer below suggested creating the calculated measure using Aggregate, but creating it on a spare dimension hierarchy rather than in the Measures dimension. This works, but only if the cross-join with the [All] member of the selected "any old..." dimension is included.
Creating the measure there also makes it impossible to put the two (base) measures and the calculated measure on the same axis. If I try to do this:
{Measures.ThingoCount,Measures.WeekTotal,[Ages].[Age Key].WeekSummedTotal} ON 0,
I get the deeply-unhelpful error message:
Members, tuples or sets must use the same hierarchies in the function.
which, I think, translates to "I can't make a set using the , (UNION) function between members of Measures and members of [Ages].[Age Key] because they're members of different dimensions".
My conclusion, thanks to your informative answers, is that Aggregate() with a single argument is a tricky beast; I wonder why it was designed with the second argument optional?
I've also noted that trying to create my calculated member on my Ages dimension (only one hierarchy, only one attribute) gives me the misleading error message:
The 'Ages' dimension contains more than one hierarchy, therefore
the hierarchy must be explicitly specified.
unless I explicitly specify the hierarchy. MDX has so much potential, but the learning curve would be that much gentler if MS had put more effort into making it feed back errors properly.
What would this do? Would Aggregate aggregate the cube's default
measure over the set? Or the set Measures.Members? Or the set of other
measures specified on the 0 axis?
Aggregate function aggregates the set over the current measure for Measures dimension. And a measure is "current" if it is in scope. If a measure is not in scope, the default member from measures dimension is considered for aggregation.
A measure can be added to scope in many ways like
Having the measure on axes
with member [Customer].[Customer].abc as
aggregate([Customer].[Customer].members)
select [Customer].[Customer].abc on 0,
{[Measures].[Internet Sales Amount],[Measures].[Reseller Sales Amount]} on 1
from [Adventure Works]
In the above example the member abc was calcualted twice, once for each measure.
Using Subcube
with member [Customer].[Customer].abc as
aggregate([Customer].[Customer].members)
select [Customer].[Customer].abc on 0
from (select {[Measures].[Internet Sales Amount] } on 0 from [Adventure Works])
Having the measure in definition
with member [Customer].[Customer].abc as
aggregate([Customer].[Customer].members, [Measures].[Internet Sales Amount])
select [Customer].[Customer].abc on 0
from [Adventure Works]
In Where clause
with member [Customer].[Customer].abc as
aggregate([Customer].[Customer].members)
select [Customer].[Customer].abc on 0
from [Adventure Works]
where [Measures].[Internet Sales Amount]
As suggested by whytheq, have the member on some other dimension-hierarchy combo. Otherwise, the aggregate function would probably lead to the calculated member self-referencing itself.
Taking this section of the MSDN definition:
...this function aggregates each measure within the current query
context ...
each measure in the context of your script is the following:
{Measures.ThingoCount,Measures.WeekTotal,Measures.WeekSummedTotal}
Now Measures.WeekSummedTotal is a calculated members in the measures dimension - hence the error.
I'd imagine something like the following would function ok, where you use Aggregate to create a member in a dimension other than Measures?:
WITH
MEMBER [SomeSpareDim].[SomeSpareHier].WeekSummedTotal AS
Aggregate
(
[Days].[WeeksAndDays].CurrentMember.Children * [SomeDim].[SomeHier].[All]
)
SELECT
[SomeSpareDim].[SomeSpareHier].WeekSummedTotal ON 0
,[Days].[WeeksAndDays].[WeekName] ON 1
FROM DateGRoupingTest;
The above can be changed to show Aggregate being very useful:
WITH
MEMBER [Days].[WeeksAndDays].[Last3Weeks] AS
Aggregate
(
{
[Days].[WeeksAndDays].[Weekx]
,[Days].[WeeksAndDays].[Weeky]
,[Days].[WeeksAndDays].[Weekz]
}
)
SELECT
{Measures.ThingoCount,Measures.WeekTotal} ON 0
,{
//<< the following custom aggregated member will work for any measure, that is ON 0, via Aggregate
//it can be mixed up with the normal members of the same hierarchy like the following
[Days].[WeeksAndDays].[Last3Weeks]
,[Days].[WeeksAndDays].[WeekName].members
} ON 1
FROM DateGRoupingTest;

Ever a need for CurrentMember.Item(0)

The custom measure in the following is taken from the book MDX Cookbook (Tomislav Piasevoli):
WITH
MEMBER [Internet Sales PP] AS
Sum
(
Generate
(
{
[Date].[Calendar].[Date].&[20080105]
:
[Date].[Calendar].[Date].&[20080125]
}
,{
ParallelPeriod
(
[Date].[Calendar].[Calendar Year]
,1
,[Date].[Calendar].CurrentMember.Item(0)
)
}
)
,[Measures].[Internet Sales Amount]
)
SELECT
{
[Measures].[Internet Sales Amount]
,[Internet Sales PP]
} ON 0
,[Product].[Color].MEMBERS ON 1
FROM [Adventure Works];
What purpose does the item(0) serve?
My understanding, which is probably wrong is
<set>.item(0) gives us first tuple in set
<tuple>.item(0) gives us first member in tuple
So what is the point of <member>.item(0)?
Refer this excellent article on the topic.
To sum it up, when we are doing a .ITEM(0) on a member, that member is implicitly converted to a tuple. So, .ITEM(0) does not really serve any purpose other than returning the member itself.
I would assume this is a typo or a copy paste error. At least in the official Microsoft MDX reference, there are only the two Item() versions that you mention.
And this does not cause an error, as there are some implicit type conversions:
If you have a member and need a tuple for the current expression, AS implicitly builds a one-member tuple from the member. Which is what takes place here presumably, when applying Item(0) to a member.
If you have a one member tuple and need a member for the current expression, AS implicitly applies Item(0).
There are similar implicit conversions from tuple and level to set, from tuple to scalar value, from dimension to hierarchy, and from hierarchy to member.

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!