Using OR condition in MDX with different hierarchies of same dimension - mdx

I would like to get data from cube where [Product].[Product Level2].&[S1050]&[S1050.080] OR [Product].[Product Level4].&[S1060.012.701003]. So combine two hierarchies from same measure in set.
SELECT NON EMPTY {
[Measures].[Product Sales], [Measures].[Sales Quantity]
} ON COLUMNS,
NON EMPTY { (
[Product].[EAN CODE].[EAN CODE].ALLMEMBERS
* [Product].[Product].[Product].ALLMEMBERS
* [Date].[Calender Week].[Calender Week].ALLMEMBERS
* [Store].[Store Code].[Store Code].ALLMEMBERS
* [Store].[Store].[Store].ALLMEMBERS
) } ON ROWS
FROM (
SELECT ( -{ [Store].[Store Code].&[0032], [Store].[Store Code].&[0033] } ) ON COLUMNS FROM (
SELECT ( { [Date].[Calender Week].&[2019]&[IW201906] } ) ON COLUMNS FROM [Cube]
)
)
WHERE (
{[Product].[Product Level2].&[S1050]&[S1050.080], [Product].[Product Level4 Code].&[S1060.012.701003]}
)
The above query is returning "Members, tuples or sets must use the same hierarchies in the function."
Thank you for helping

You need to write your where like this
{(
[Product].[Product Level2].&[S1050]&[S1050.080], [Product].[Product Level4 Code].defaultmember),
{[Product].[Product Level2].defaultmember, [Product].[Product Level4 Code].&[S1060.012.701003]}
)

Related

Top X of Top Y with RestOf member where X and Y are hierarchies from different dimensions

This works fine:
WITH
SET [AllCountries] AS [Country].[Country].MEMBERS
SET [AllStates] AS [State-Province].[State-Province].MEMBERS
SET [Top2States] AS
Generate
(
[AllCountries]
,TopCount
(
(EXISTING
[AllStates])
,3
,[Measures].[Internet Order Count]
)
)
MEMBER [State-Province].[All].[RestOfCountry] AS
Aggregate({(EXISTING {[AllStates]} - [Top2States])})
SELECT
{[Measures].[Internet Order Count]} ON COLUMNS
,{
[AllCountries]
*
{
[State-Province].[All]
,[Top2States]
,[State-Province].[All].[RestOfCountry]
}
} ON ROWS
FROM [Adventure Works];
The EXISTING keyword helps a lot .
If the two hierarchies ON ROWS are not from the same dimension, in the way that countries and states are in the above, then we have something like the following:
WITH
SET [AllCountries] AS [Country].[Country].MEMBERS
SET [AllCats] AS [Product].[Category].[Category].MEMBERS
SET [Top5Cats] AS
Generate
(
[AllCountries]
,TopCount
(
(EXISTING
[AllCats])
,5
,[Measures].[Internet Order Count]
)
)
MEMBER [Product].[Category].[All].[RestOfProds] AS
Aggregate({(EXISTING {[AllCats]} - [Top5Cats])})
SELECT
{[Measures].[Internet Order Count]} ON COLUMNS
,{
[AllCountries]
*
{
[Product].[Category].[All]
,[Top5Cats]
,[Product].[Category].[All].[RestOfCountry]
}
} ON ROWS
FROM [Adventure Works];
You can see in the results of the above that the same set of categories are repeated against each country, in the same order i.e. the engine is not finding the topCount per country. EXISTING is now redundant.
How can we adapt the second script above so that it has similar functionality as the top script?
Edit
A better example is the following using Product. It is as if the engine is finding the TopCount for All countries and then putting the same set against each country. I'd like the TopCount for each country:
WITH
SET [AllCountries] AS
[Country].[Country].MEMBERS
SET [AllProds] AS
[Product].[Product].[Product].MEMBERS
SET [Top5Prods] AS
Generate
(
[AllCountries]
,TopCount
(
(EXISTING
[AllProds])
,5
,[Measures].[Internet Order Count]
)
)
MEMBER [Product].[Product].[All].[RestOfProds] AS
Aggregate({(EXISTING {[AllProds]} - [Top5Prods])})
SELECT
{[Measures].[Internet Order Count]} ON COLUMNS
,NON EMPTY
{
[AllCountries]
*
{
[Product].[Product].[All]
,[Top5Prods]
,[Product].[Product].[All].[RestOfProds]
}
} ON ROWS
FROM [Adventure Works];
Edit2
This is the latest version via Sourav's ideas - unfortunately the RestOfProds members are not functioning correctly:
WITH
SET [AllCountries] AS
[Country].[Country].MEMBERS
SET [AllProds] AS
[Product].[Product].[Product].MEMBERS
SET [Top5Prods] AS
Generate
(
[AllCountries] AS a
,
{
(
a.Current
,[Product].[Product].[All]
)
+
//The top x prods
TopCount
(
NonEmpty
(
a.Current * [AllProds]
,[Measures].[Internet Sales Amount]
)
,5
,[Measures].[Internet Sales Amount]
)
}
)
SET [RestOfProds] AS
Extract
(
{[AllCountries] * [AllProds]} - [Top5Prods]
,[Product].[Product]
)
MEMBER [Product].[Product].[All].[RestOfProds] AS
Aggregate([RestOfProds])
SELECT
{[Measures].[Internet Sales Amount]} ON COLUMNS
,{
[Top5Prods]
,
[AllCountries] * [Product].[Product].[All].[RestOfProds]
} ON ROWS
FROM [Adventure Works];
Edit3
The following has the correct order so that the member RestOfProds always follows it's respective top 5
WITH
SET [AllCountries] AS
[Country].[Country].MEMBERS
SET [AllProds] AS
[Product].[Product].[Product].MEMBERS
SET [Top5Prods] AS
Generate
(
[AllCountries] AS a
,{
//The top x prods
TopCount
(
NonEmpty
(
a.Current * [AllProds]
,[Measures].[Internet Sales Amount]
)
,5
,[Measures].[Internet Sales Amount]
)
}
)
MEMBER [Product].[Product].[All].[RestOfProds] AS
Aggregate([Country].CurrentMember * [AllProds] - [Top5Prods])
SELECT
{[Measures].[Internet Sales Amount]} ON COLUMNS
,Generate
(
[AllCountries] AS X
,
Order
(
Intersect
(
X.CurrentMember * [AllProds]
,[Top5Prods]
)
,[Measures].[Internet Sales Amount]
,bdesc
)
+
{X.CurrentMember * {[Product].[Product].[All].[RestOfProds]}}
) ON ROWS
FROM [Adventure Works];
Edit4
The following has the correct order so that the member RestOfProds always follows it's respective top 5 + I've added a further set on rows:
WITH
SET [2months] AS
{
[Date].[Calendar].[Month].&[2007]&[9]
,[Date].[Calendar].[Month].&[2007]&[10]
}
SET [AllCountries] AS
[Country].[Country].MEMBERS
SET [MthsCountries] AS
[2months] * [AllCountries]
SET [AllProds] AS
[Product].[Product].[Product].MEMBERS
SET [Top5Prods] AS
Generate
(
[MthsCountries] AS A
,{
//The top x prods
TopCount
(
NonEmpty
(
A.Current * [AllProds]
,[Measures].[Internet Sales Amount]
)
,5
,[Measures].[Internet Sales Amount]
)
}
)
MEMBER [Product].[Product].[All].[RestOfProds] AS
Aggregate
(
([Date].[Calendar].CurrentMember,[Country].CurrentMember) * [AllProds]
-
[Top5Prods]
)
SELECT
{[Measures].[Internet Sales Amount]} ON COLUMNS
,Generate
(
[MthsCountries] AS X
,
Order
(
Intersect
(
X.Current * [AllProds]
,[Top5Prods]
)
,[Measures].[Internet Sales Amount]
,bdesc
)
+
{X.Current * {[Product].[Product].[All].[RestOfProds]}}
) ON ROWS
FROM [Adventure Works];
EXISTING when used on named sets, doesn't really make a difference since named sets are created before the axes members are laid out. In your case, GENERATE is really just creating static sets and then on the axes everything is just cross joined.
To get the TopCount script working, you need to handle all the cross joins inside one set so that everything is evaluated together. I am not sure, but you might try the below:
WITH
SET [AllCountries] AS [Country].[Country].MEMBERS
SET [AllCats] AS [Product].[Category].[Category].MEMBERS
SET [Top5Cats] AS
Generate
(
[AllCountries] as a
,
{
(a.current , [Product].[Category].[All] ) //The ALL member
+
TopCount //The top 2 categories
(
NonEmpty((a.current * [AllCats] ) , (a.CURRENT, [Measures].[Internet Order Count]))
,2
,[Measures].[Internet Order Count]
)
}
+
{ //The rest of the members
a.current * [AllCats]
-
a.current *{
TopCount
(
NonEmpty([AllCats] , (a.CURRENT, [Measures].[Internet Order Count]))
,2
,[Measures].[Internet Order Count]
)
}
}
)
MEMBER [Product].[Category].[All].[RestOfProds] AS
Aggregate({(EXISTING {[AllCats]} - [Top5Cats])})
SELECT
{[Measures].[Internet Order Count]} ON COLUMNS,
[Top5Cats] ON ROWS
FROM [Adventure Works];
EDIT:
If you need the RestOfCats member, you can add this code.
SET [RestOfCats] AS
EXTRACT
(
{
[AllCountries] * [AllCats]
-
[Top5Cats]
},
[Product].[Category]
)
MEMBER [Product].[Category].[All].[RestOfCats] AS
Aggregate([RestOfCats])
EDIT 2
Continuing on your example, removing the 'All' member additionally in the definition.
SET [RestOfProds] AS
Extract
(
{[AllCountries] * [AllProds]} - [Top5Prods] - [AllCountries]*[Product].[Product].[All]
,[Product].[Product]
)
If you are crossjoining multiple hierarchies in the same dimension only valid combinations will be shown. This is called auto-exists and it explains why the first query works like you want.
When crossjoining hierarchies from different dimensions the auto-exists does not happen. I think this explains the odd combinations returned in the second query.
Try adding NON EMPTY at the beginning of your ON ROWS definition. Then it will only return combinations which have an Internet Order Count measure value (whatever measures are on columns). That's the proper way to limit the crossjoin.
If you don't want a NON EMPTY on Internet Order Count then so you need a NonEmpty(, [Measures].[A Different Measure]) on a different measure?
Edit: It looks like the issue is not related to auto-exists but is related to performing a different TopCount per country. So this info may help someone else but isn't the answer to this question.
This seems to work ok:
WITH
SET [AllCountries] AS
[Country].[Country].MEMBERS
SET [AllProds] AS
[Product].[Product].[Product].MEMBERS
SET [Top5Prods] AS
Generate
(
[AllCountries] AS a
,{
(
a.CurrentMember
,[Product].[Product].[All]
)
+
//The top x prods
a.CurrentMember
*
TopCount
(
[AllProds]
,5
,[Measures].[Internet Sales Amount]
)
}
)
MEMBER [Product].[Product].[All].[Other Products] AS
Aggregate
(
[Country].CurrentMember * [Product].[Product].[Product].MEMBERS
-
[Top5Prods]
)
SELECT
{[Measures].[Internet Sales Amount]} ON COLUMNS
,Hierarchize(
{
[Top5Prods]
,[AllCountries] * [Product].[Product].[All].[Other Products]
}
) ON ROWS
FROM [Adventure Works];

How would you order MDX query

I am unable to figure out how I would do a simple "order by" clause.
Below is my query - how would I order it by Service Name then by Adjusted Incidents?
SELECT
{[Measures].[Adjusted Incidents]} ON COLUMNS
,NON EMPTY
{
[Completed Inspections].[Service Name].[Service Name].ALLMEMBERS
*
[Inspected Items].[Item Name].[Item Name].ALLMEMBERS
}
DIMENSION PROPERTIES MEMBER_CAPTION ON ROWS
FROM
(
SELECT
{
[Completed Inspections].[Customer Id].&[DRHOD]
,[Completed Inspections].[Customer Id].&[EMHST]
,[Completed Inspections].[Customer Id].&[EXHOU]
,[Completed Inspections].[Customer Id].&[ETRAD]
} ON COLUMNS
FROM [Inspections]
)
WHERE
(
[Calendar].[Month].&[2015-05-01T00:00:00]
,[Completed Inspections].[Is Reinspection].&[False]
)
CELL PROPERTIES VALUE;
There isn't a clause for order in mdx similar to sql.
You need to apply the function ORDER to any sets that you wish to order. Here is the msdn definition:
https://msdn.microsoft.com/en-us/library/ms145587.aspx
Nesting orders isn't so trivial in mdx - the inside application of order is the order you want applied second the outside nest is the order you want applied first:
SELECT
{[Measures].[Adjusted Incidents]} ON COLUMNS
,NON EMPTY
Order
(
Order
(
{
[Completed Inspections].[Service Name].[Service Name].ALLMEMBERS
*
[Inspected Items].[Item Name].[Item Name].ALLMEMBERS
}
,[Measures].[Adjusted Incidents]
,BDESC //<<you have 4 choices here BDESC, BASC, DESC, or ASC
)
,[Completed Inspections].[Service Name].CurrentMember.Member_Caption
,BDESC //<<you have 4 choices here BDESC, BASC, DESC, or ASC
)
DIMENSION PROPERTIES MEMBER_CAPTION ON ROWS
FROM
(
SELECT
{
[Completed Inspections].[Customer Id].&[DRHOD]
,[Completed Inspections].[Customer Id].&[EMHST]
,[Completed Inspections].[Customer Id].&[EXHOU]
,[Completed Inspections].[Customer Id].&[ETRAD]
} ON COLUMNS
FROM [Inspections]
)
WHERE
(
[Calendar].[Month].&[2015-05-01T00:00:00]
,[Completed Inspections].[Is Reinspection].&[False]
)
CELL PROPERTIES VALUE;

Filtered Parameters MDX error

New to mdx and trying to filter one parameter. I have the following,
WITH MEMBER [Measures].[ParameterCaption] AS IIF(IsEmpty([Measures].[Charge Count]),null, [Payment].[Description].CurrentMember .MEMBER_CAPTION)
MEMBER [Measures].[ParameterValue] AS IIF(IsEmpty([Measures].[Charge Count]), null, [Payment].[Description].CurrentMember.UniqueName)
MEMBER [Measures].[ParameterLevel] AS IIF(IsEmpty([Measures].[Charge Count]), null, [Payment].[Description].CurrentMember .Level .Ordinal)
SELECT
{ [Measures].[ParameterCaption],
[Measures].[ParameterValue],
[Measures].[ParameterLevel] } ON COLUMNS
, NONEMPTY ([Primary].[Description].ALLMEMBERS, [Measures].[Charge Count]) ON ROWS
FROM (SELECT (STRTOSET(#Client, CONSTRAINED) ON COLUMNS
FROM [DACUBE]))
with an error on the second to last line with the 'ON'. This all seems correct except this error. Can someone tell me where I'm going wrong?
I think your braces are not quite correct - try the following:
WITH
MEMBER [Measures].[ParameterCaption] AS
IIF
(
IsEmpty([Measures].[Charge Count])
,null
,[Payment].[Description].CurrentMember.Member_Caption
)
MEMBER [Measures].[ParameterValue] AS
IIF
(
IsEmpty([Measures].[Charge Count])
,null
,[Payment].[Description].CurrentMember.UniqueName
)
MEMBER [Measures].[ParameterLevel] AS
IIF
(
IsEmpty([Measures].[Charge Count])
,null
,[Payment].[Description].CurrentMember.Level.Ordinal
)
SELECT
{
[Measures].[ParameterCaption]
,[Measures].[ParameterValue]
,[Measures].[ParameterLevel]
} ON COLUMNS
,NonEmpty
(
[Primary].[Description].ALLMEMBERS
,[Measures].[Charge Count]
) ON ROWS
FROM
(
SELECT
StrToSet
(#Client
,CONSTRAINED
) ON COLUMNS
FROM [DACUBE]
);

Ordering a complex set

I've been playing with a script of Chris Webb's found here: http://cwebbbi.wordpress.com/2007/06/25/advanced-ranking-and-dynamically-generated-named-sets-in-mdx/
The adapted script is this:
WITH
SET MyMonths AS
TopPercent
(
[Date].[Calendar].[Month].MEMBERS
,20
,[Measures].[Reseller Sales Amount]
)
SET MyEmployees AS
[Employee].[Employee].[Employee].MEMBERS
SET MyMonthsWithEmployeesSets AS
Generate
(
MyMonths
,Union
(
{[Date].[Calendar].CurrentMember}
,StrToSet
("
Intersect({},
{TopCount(MyEmployees, 10, ([Measures].[Reseller Sales Amount],[Date]. [Calendar].CurrentMember))
as EmployeeSet"
+
Cstr(MyMonths.CurrentOrdinal)
+ "})"
)
)
)
MEMBER [Employee].[Employee].[RestOfEmployees] AS
Aggregate
(
Except
(
MyEmployees
,StrToSet
(
"EmployeeSet" + Cstr(Rank([Date].[Calendar].CurrentMember,MyMonths))
)
)
)
MEMBER [Measures].[EmployeeRank] AS
Rank
(
[Employee].[Employee].CurrentMember
,StrToSet
(
"EmployeeSet" + Cstr(Rank([Date].[Calendar].CurrentMember,MyMonths))
)
)
SELECT
{
[Measures].[EmployeeRank]
,[Measures].[Reseller Sales Amount]
} ON 0
,Hierarchize
(
Union
(
Filter
(
MyMonthsWithEmployeesSets * MyEmployees //<<<HERE<<<<
,
[Measures].[EmployeeRank] >= 1
)
,{
MyMonthsWithEmployeesSets * [Employee].[Employee].[RestOfEmployees]
}
)
) ON 1
FROM [Adventure Works];
How do I ORDER the output so that each set of ten employees is in order 1 to 10, with the MEMBER called RestOfEmployees always found in position 11 i.e. it should follow the member ranked 10 ?
The temptation is to add the ORDER function at the point marked HERE i.e. that line will become :
MyMonthsWithEmployeesSets * ORDER(MyEmployees, [Measures].[EmployeeRank])
Doing that results in the following error message:
The dimension '[EmployeeSet0]' was not found in the cube when the string, [EmployeeSet0], was parsed.
I believe this is because the measure EmployeeRank uses the inline sets created during the generate function.
If you redefine EmployeeRank to be 11 for RestOfEmployees, you can just add that member to the set that is the first argument to Filter, and than apply Order, as it will sort after position 1 to 10:
WITH
SET MyMonths AS
TopPercent
(
[Date].[Calendar].[Month].MEMBERS
,20
,[Measures].[Reseller Sales Amount]
)
SET MyEmployees AS
[Employee].[Employee].[Employee].MEMBERS
SET MyMonthsWithEmployeesSets AS
Generate
(
MyMonths
,Union
(
{[Date].[Calendar].CurrentMember}
,StrToSet
("
Intersect({},
{TopCount(MyEmployees, 10, ([Measures].[Reseller Sales Amount],[Date]. [Calendar].CurrentMember))
as EmployeeSet"
+
Cstr(MyMonths.CurrentOrdinal)
+ "})"
)
)
)
MEMBER [Employee].[Employee].[RestOfEmployees] AS
Aggregate
(
Except
(
MyEmployees
,StrToSet
(
"EmployeeSet" + Cstr(Rank([Date].[Calendar].CurrentMember,MyMonths))
)
)
)
MEMBER [Measures].[EmployeeRank] AS
IIF([Employee].[Employee].CurrentMember IS [Employee].[Employee].[RestOfEmployees],
11,
Rank
(
[Employee].[Employee].CurrentMember
,StrToSet
(
"EmployeeSet" + Cstr(Rank([Date].[Calendar].CurrentMember,MyMonths))
)
)
)
SELECT
{
[Measures].[EmployeeRank]
,[Measures].[Reseller Sales Amount]
} ON 0
,
Order(
Filter
(
MyMonthsWithEmployeesSets
* UNION(MyEmployees, {[Employee].[Employee].[RestOfEmployees]})
,
[Measures].[EmployeeRank] >= 1
), [Measures].[EmployeeRank]
)
ON 1
FROM [Adventure Works];

Measure lacking context

I am struggling to force the measure CountTopPromos to be contextual.
Currently it is calculating a count of all the tuples in TopX. Against the version of AdWrks that I am running this is 14.
How do I force a context, of the current year, onto the measure CountTopPromos
WITH
SET FullSet AS
NonEmpty
(
[Date].[Calendar].[Calendar Year].MEMBERS
*
[Promotion].[Promotion].MEMBERS
,[Measures].[Reseller Order Count]
)
SET TopX AS
Generate
(
[Date].[Calendar].[Calendar Year].MEMBERS
,TopPercent
(
[Date].[Calendar].CurrentMember
*
Extract
(
FullSet
,[Promotion].[Promotion]
)
,90
,[Measures].[Reseller Order Count]
)
)
MEMBER [Measures].[CountTopPromos] AS
Count(TopX) //<<<<<<<<<<<< CONTEXT LACKING HERE <<<<<<<
SELECT
NON EMPTY
{[Measures].[CountTopPromos]} ON 0
,{TopX} ON 1
FROM [Adventure Works];
Currently it returns the following:
I'd like CountTopPromos to be in the context of the year so the desired output is as follows:
As sets are evaluated before the axes are defined (see my answer to this question), you cannot get row context into the calculation if you use the named set TopX. You could, however, copy its definition into the definition of [Measures].[CountTopPromos], replacing [Date].[Calendar].[Calendar Year].MEMBERS with [Date].[Calendar].CurrentMember:
MEMBER [Measures].[CountTopPromos] AS
Count(
Generate
(
[Date].[Calendar].currentMember
,TopPercent
(
[Date].[Calendar].CurrentMember
*
Extract
(
FullSet
,[Promotion].[Promotion]
)
,90
,[Measures].[Reseller Order Count]
)
)
)
delivers the result you want. And - as the Generate would loop over just one member here - you could omit that as well:
MEMBER [Measures].[CountTopPromos] AS
Count(
TopPercent
(
[Date].[Calendar].CurrentMember
*
Extract
(
FullSet
,[Promotion].[Promotion]
)
,90
,[Measures].[Reseller Order Count]
)
)
and will get the same result.
Another alternative that is quite pretty:
MEMBER [Measures].[CountTopPromos] AS
Count
(
Intersect
(
{
[Date].[Calendar].CurrentMember * [Promotion].[Promotion].MEMBERS
}
,TopX
)
)