MDX to show Measure property - ssas

I'm familiar with how to get member properties into an MDX result-set: create a calculated member using WITH.
The problem is when the member whose properties I want is a measure, not a dimension member. Because the calculated member is created on the Measures hierarchy, I get the dreaded "The Measures hierarchy already appears in the Axis0 axis" error. Here's the query I'm running:
WITH MEMBER Measures.MeasureType AS
Measures.CurrentMember.Properties('MEMBER_TYPE')
SELECT
MeasureType ON 0,
Measures.Members on 1
FROM TheCube
What I'm after is simply a list of all the measures ON 1 (this works, in itself); but with the measure's MEMBER_TYPE showing as the one column ON 0

You can't have members from the same hierarchy on both axes. There are two ways to get rid of this error.
1. Create the calculated member on some other dimension
WITH MEMBER [SomeDimension].[SomeHierarchy].MeasureType AS
Measures.CurrentMember.Properties('MEMBER_TYPE')
SELECT
[SomeDimension].[SomeHierarchy].MeasureType ON 0,
Measures.Members on 1
FROM [TheCube]
2. Have them in a set and not on different axes.
WITH MEMBER Measures.MeasureType AS
Measures.CurrentMember.Properties('MEMBER_TYPE')
SELECT
{Measures.MeasureType, Measures.Members} ON 0
FROM [TheCube]
Discarding the second method as it gives a static value. What's really needed is a cross-tab value. So sticking with first method.

Related

MDX Result Count

I am a beginner in MDX queries. Can any one tell me how to get the record count that is a result of a MDX query?
The query is following:
select {[Measures].[Employee Department History Count],[Measures].[Rate]} on columns, Non Empty{{Filter([Shift].[Shift ID].[Shift ID].Members, ([Shift].[Shift ID].CurrentMember.name <> "1"))}*{[Employee].[Business Entity ID].[Business Entity ID].Members}} on rows from [Adventure Works2012].
I have tried various methods and I haven't really got a solution for that.
I assume you mean row count when you talk of "record count", as MDX does not know a concept of records, but the result shown from an MDX query is the space built by the tuples on the axes.
I see two possibilities to get the row count:
Just count the rows returned from your above query in the tool from which you call the MDX query.
If you want to count in MDX, then let's state what you want to have:
You want to know the number of members of the set of non empty combinations of [Shift ID]s and [Business Entity ID]s where the Shift ID is not "1" and at least one of the measures [Employee Department History Count] and [Rate] is not null.
To state that different: Let's call the tuples like above for which the first measure is not null "SET1", and the tuples like above for which teh second measure is not null "SET2". Then you you want to know the count of the the tuples which are contained in one of these sets (or in both).
To achieve this, we define these two sets and then a calculated menber (a new measure in our case) containing this calculation in its definition, and then use this calculated member in the select clause to show it:
WITH
SET SET1 AS
NonEmpty({{Filter([Shift].[Shift ID].[Shift ID].Members,
([Shift].[Shift ID].CurrentMember.name <> "1"))}
* {[Employee].[Business Entity ID].[Business Entity ID].Members}},
{[Measures].[Employee Department History Count])
SET SET2 AS
NonEmpty({{Filter([Shift].[Shift ID].[Shift ID].Members,
([Shift].[Shift ID].CurrentMember.name <> "1"))}
* {[Employee].[Business Entity ID].[Business Entity ID].Members}},
{[Measures].[Rate])
MEMBER [Measures].[MyCalculation] AS
COUNT(SET1 + SET 2)
SELECT [Measures].[MyCalculation] ON COLUMNS
FROM [Adventure Works2012]
Please note:
The sets SET1 and SET2 are not absolutely necessary, you could also put the whole calculation in one long and complicated definition of the MyCalculation measure, but splitting it up makes is easier to read. However, the definition of a new member is necessary, as in MDX you can only put members on axes (rows, columns, ...). These members can either already been defined in the cube, or you have to define them in the WITH clause of your query. There is no such thing as putting expressions/calculations on axes in MDX, only members.
The + for sets is a union which removes duplicates, hence this operation gives us the tuples which have an non empty value for at least one of the measures. Alternatively, you could have used the Union function equivalently to the +.
The Nonempty() I used in the definitions of the sets is the NonEmpty function, which is slightly different from the NON EMPTY keyword that you can use on the axes. We use one of the measures as second argument to this function in both set definitions.
I have currently no working SSAS installation available to test my statement, hence there might be a minor error or typo in my above statement, but the idea should work.

MDX Statement explaination required

Please explain the below MDX statement -
Axis(1).Item(0).Item (0).Dimension.Levels(0).item(0)
If possible please share the output as well (using SSMS analysis services)
Axis(1).Item(0).Item(0).Dimension.Levels(0).Item(0)
The way to figure out what this expression means, is to go through each function from left-to-right, and determine what each one is doing and returning. Let's go through this one function at a time.
Axis(1) - Retrieve the set of tuples on the rows axis (the axis at index 1).
Item(0) - Retrieve the first tuple from the previously returned set.
Item(0) - Retrieve the first member from the previously returned tuple.
Dimension - Get the hierarchy from the previously returned member.
Levels(0) - Retrieve the first level from the previously returned hierarchy.
Item(0) - Retrieve the first member from the previously returned hierarchy level.
Here are the Microsoft function definitions that I used to create the above list.
Axis()
Returns the set of tuples on a specified axis.
Item(Tuple)
Returns a tuple from a set.
Item(Member)
Returns a member from a specified tuple.
Dimension
Returns the hierarchy that contains a specified member, level, or hierarchy.
Levels()
Returns the level whose position in a dimension or hierarchy is specified by a numeric expression or whose name is specified by a string expression.
Edit - Added Example
Check out the Geography dimension and hierarchy from the Adventure Works cube.
There are 5 levels for the Geography hierarchy.
[Geography].[Geography].[(All)]
[Geography].[Geography].[Country]
[Geography].[Geography].[State-Province]
[Geography].[Geography].[City]
[Geography].[Geography].[Postal Code]
Let's use your expression on the columns axis (via a calculated member) and select the city, Alexandria, on the rows axis.
WITH
MEMBER [Measures].[SomeMember] AS AXIS(1).ITEM(0).ITEM(0).DIMENSION.LEVELS(0).ITEM(0).MEMBER_CAPTION
SELECT
{([Measures].[SomeMember])} ON COLUMNS,
{([Geography].[Geography].[City].&[Alexandria]&[NSW])} ON ROWS
FROM
[Adventure Works]
Here is the break-down of what's happening:
Axis(1) - Returns the set from the rows axis:
{([Geography].[Geography].[City].&[Alexandria]&[NSW])}
ITEM(0) - Returns the set's first tuple:
([Geography].[Geography].[City].&[Alexandria]&[NSW])
ITEM(0) - Returns the tuple's first member:
[Geography].[Geography].[City].&[Alexandria]&[NSW]
DIMENSION - Returns the member's dimension hierarchy:
[Geography].[Geography]
LEVELS(0) - Returns the hierarchy's first level:
[Geography].[Geography].[(All)]
ITEM(0) - returns the level's first member:
[Geography].[Geography].[(All)].[All Geographies]
Here are the query results:
Here is a screenshot to help visualize where the All Geographies member is, with respect to the Alexandria member:

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;

Set 0 for specific value MDX query

I've been looking around for the answer but I didn't find anything. Sorry if the answer has been given elsewhere.
Here is my problem :
I have a calculated member which is the number of items (of the current member) divided by the total number of items (sumitem).
with
member
sumitem
as
SUM ([FailureReason].[FailureReason].[All],[Measures].[Items])
member
Impact
as
[Measures].[Items]/[Measures].[SumItem]
But for a specific member of my dimension FailureReason, the result of Impact has to be 0. So I tried to add this :
member
ImpactFinal
as
iif ([FailureReason].CurrentMember = [FailureReason].[FailureReason].&[127],
0,
Impact
)
and I select my data like this :
select
{[Measures].[Items],
ImpactFinal
} on columns,
[FailureReason].members on rows
from
NoOTAR
But instead of getting 0 only for this specific member, every members of this dimension have their ImpactFinal equals to 0. What is strange is if I replace 0 by any other value, the result is good.
Just use
[FailureReason].CurrentMember IS [FailureReason].[FailureReason].&[127]
instead of
[FailureReason].CurrentMember = [FailureReason].[FailureReason].&[127]
and it will work.
Update: Several tips:
There is also not necessary to use SUM function, since you can define only tuple, this will be enough for server: ([FailureReason].[FailureReason].[All],[Measures].[Count])
It's quite reasonable to check sumitem measure for dividing by zero in ImpactFinal calculation. Because once some filters are applied, this may cause zeroing this measure and errors in reports.
If you have an opportunity not only to query, but update cube, SCOPE ([FailureReason].[FailureReason].&[127],[Measures].[Impact]) with THIS = 0 is better than additional member because of performance.
Best of luck!
UPDATE to fix totals:
If total should be w/o FailureReason 127, you can substitute your measures with:
member Impact
as
iif ([FailureReason].[FailureReason].CurrentMember is [FailureReason].[FailureReason].&[127],
0,
[Measures].[Items]
)
member ImpactFinal
as
iif ([FailureReason].[FailureReason].CurrentMember is [FailureReason].[FailureReason].[All]
,[Measures].[Items]-([FailureReason].[FailureReason].&[127],[Measures].[Items])
,[Measures].[Impact])/[Measures].[SumItem]
But I have another solution, which is more readable:
member v2_ImpactUncountableFailure
as
iif ([FailureReason].[FailureReason].CurrentMember.Level.Ordinal=0
or
[FailureReason].[FailureReason].CurrentMember is [FailureReason].[FailureReason].&[127]
,([FailureReason].[FailureReason].&[127],[Measures].[Items])
,null)
member v2_ImpactFinal
as
([Measures].[Items]-[Measures].[v2_ImpactUncountableFailure])
/
([FailureReason].[FailureReason].[All],[Measures].[Items])
Use only this two measures instead of set of measures sumitem,Impact,ImpactFinal. First one will show result on failure-127 and total. Second subtracts it from clean unfiltered measure, so in the end we have clean members, zeroed failure-127 and corrected total.
Please let me know if it isn't work, I've tested on my DB and everything is OK.
A simple CASE statement would solve your problem: Try this
With
Member ImpactFinal As
CASE
WHEN [FailureReason].[FailureReason].CurrentMember IS [FailureReason].[FailureReason].&[127] THEN 0
ELSE
[Measures].[Items]
/
([FailureReason].[FailureReason].[All], [Measures].[Items])
END
SELECT
{ [Measures].[Items], ImpactFinal } On Columns
[FailureReason].[FailureReason].Members On Rows
From NoOTAR
Try
with
member sumitem
as
SUM ([FailureReason].[FailureReason].[All],[Measures].[Items])
member LeaveOut
as
[FailureReason].[FailureReason].CurrentMember.Properties("Key")
member Impact
as
IIf([Measures].[LeaveOut]= "127", 0, [Measures].[Items]/[Measures].[SumItem])

Create dynamic calculated member based on dimensions selected ON ROWS

Is there a way to create a dynamic calculated member based on the dimension selected ON ROWS?
I have the following example with 2 dimensions [Dim1].[Dim1] and [Dim2].[Dim2], with a measure [Measures].[Measure] and a calculated member [Measures].[CalculatedMeasure]:
WITH MEMBER [Measures].[CalculatedMeasure] AS
IIF([Dim1].[Dim1]**.....IS SELECTED ON ROWS.........**,
[Measures].[Measure]
/
([Measures].[Measure], [Dim1].[Dim1].CurrentMember.Parent),
[Measures].[Measure]
/
([Measures].[Measure], [Dim2].[Dim2].CurrentMember.Parent))
SELECT {[Measures].[Measure],[Measures].[CalculatedMeasure]} ON COLUMNS ,
{[Dim2].[Dim2].Members)} ON ROWS
FROM [DataBase]
What I want is that when I select [Dim2].[Dim2] ON ROWS, the calculated member should be the result of
[Measures].[Measure]
/
([Measures].[Measure], [Dim2].[Dim2].CurrentMember.Parent)
ELSE
[Measures].[Measure]
/
([Measures].[Measure], [Dim1].[Dim1].CurrentMember.Parent)
Thanks
In Analysis Services, your [Dim1].[Dim1]**.....IS SELECTED ON ROWS.........** could be coded as
Axis(1).Item(0).Item(0).Hierarchy IS [Dim1].[Dim1]
if you can assume there is only one hierarchy on the rows.
Here, Axis(1) returns the rows axis as set. I am not sure if this function is supported by Pentaho/Mondrian. Then, the first Item(0) selects the first tuple of this set, and the second one returns the first member of that tuple. Finally, the Hierarchy function returns the hierarchy of a member.
To extend this to queries containing up to three hierarchies in the rows, you would write
Axis(1).Item(0).Item(0).Hierarchy IS [Dim1].[Dim1] OR
Axis(1).Item(0).Item(1).Hierarchy IS [Dim1].[Dim1] OR
Axis(1).Item(0).Item(2).Hierarchy IS [Dim1].[Dim1]