Calculate children values without taking into account grandchildren in a hiearchy - mdx

I've got a hierarchy setup in my OLAP-cube and I would like to calculate the child values from a specific node without taking into account the childrens children.
SELECT
[Colset]
,[RowSet] ON 1
FROM [Hierarchy].[Tree].&[24089].Children
If I execute this query I get sum for every child throughout the hierarchy. (Which of course is want you want in 99% of the cases). I instead would like to get the childrens values without the grandchildren.
What I like to do is something like this (pseudo-code)
SELECT
[Colset]
,[RowSet] ON 1
FROM Except( [Hierarchy].[Tree].&[24089].Children, [Hierarchy].[Tree].&[24089].GrandChildren)
Is this possible, and if, how?

Assuming SUM aggregation for your measure, something like that should do it:
with member val as sum( [Hierarchy].[Tree].&[24089], [Measures].currentMember )
- sum( descendants( [Hierarchy].[Tree].&[24089], 1, SELF ), [Measures].currentMember )
select ... where val

Related

Using Multiple Descendants in the same crossjoin

I'm trying to use multiple members within the same dimension (in the same crossjoin) to have level 0 descendants.
I'd like it to be somehting like this:
Crossjoin(
{Descendants(
[LB_PL_HOME],[LOB].levels(0)
)
,Descendants(
[LB_PL_OTH],[LOB].levels(0)
)
},
Only I can't get the syntax to work.
Any ideas on how to do this?
This is not going to work:
Descendants(
[LB_PL_HOME]
,[LOB].levels(0)
)
Well I assume it won't work as it doesn't look like [LB_PL_HOME] and [LOB] are related - you're only allowed to find members at a specified level for a member within the same dimension. e.g. for a specified Year I would be allowed to find the members at the Day level, as Year and Day are related.
If [LB_PL_HOME] and [LOB] are from different dimensions then you could do something like this:
NonEmpty(
[LOB].levels(0).MEMBERS
,[LB_PL_HOME]
)
Your next problem is that you're not allowed to crossjoin members from the same hierarchy but you could chuck them all into the same set:
{
NonEmpty(
[LOB].levels(0).MEMBERS
,[LB_PL_HOME]
)
,NonEmpty(
[LOB].levels(0).MEMBERS
,[LB_PL_OTH]
)
}

MDX where clause in subquery does not slice cube - how to understand?

This query gives me sales of one store:
select
[measures].[sales] on 0
from [MyCube]
where [store].[store].[042]
However, if I move the slicer to inside of the subquery, it gives me sales of all stores.
select
[measures].[sales] on 0
from (select
from [MyCube]
where [store].[store].[042]
)
How to understand the mechanisms behind this difference?
This is also noted in this article, but without much explanation.
----EDIT----:
I tried various things and read around for a while. I'd like to add a question: is there a scenario in which the where clause in sub-select does filter the result?
This query gives me sales of all stores in state MI (store [042] belongs to MI):
select
[measures].[sales] on 0
from (select
[store].[state].[MI] on 0
from [myCube]
where [store].[store].[042]
)
Thinking of 'inner query only filters if the filtered dimension is returned on an axis', the theory is proved wrong if I do this:
select
[measures].[sales] on 0
from (select
[store].[state].members on 0
from [myCube]
where [store].[store].[042]
)
The sub-select still returns one state MI, but the outer query returns sales of all stores (of all states).
----EDIT 4/13----:
Re-phrasing the question in AdventureWorks cube with screenshot.
Query 1: sales of one store
Query 2: it returns sales of all stores if where clause is in the sub-select.
Query 3: the two answers I got suggested that we select the dimension in an axis - here is the result - we get all cities.
select
[measures].[sales] on 0
from (select
from [MyCube]
where [store].[store].[042]
)
The above query reduces the scope of stores just to the member [042]. Make note that sub-select is executed before the actual select. So, when it comes to the select, the engine just sees a cube which has all the members in all the dimensions; but only the member [store].[store].[042] in the store dimension. It's as if the cube has been kept intact every where else but sliced off on the Store dimension.
If you go a step ahead and add the store on to one of the axes, like
select
[measures].[sales] on 0,
[store].[store].members on 1
from (select
from [MyCube]
where [store].[store].[042]
)
you would see that although the member [All] appears in the output, it actually is just comprised of only one store.
In essence, the [All] is a special member which is calculated with respect to scope of the cube. It reflects the combined effect of all the members in the cube.
In SQL terms, it is similar to:
select sales, store as [All] from
(select sales, store from tbl where store = '042') tbl
Even though you see Sales----All, it is but a reflection of sales for store [042]
Here are some other good references concerning sub-select and slicer debate:
http://bisherryli.com/2013/02/08/mdx-25-slicer-or-sub-cube/
https://cwebbbi.wordpress.com/2014/04/07/free-video-on-subselects-in-mdx/
Chris Webb's video being located here:
https://projectbotticelli.com/knowledge/what-is-a-subselect-mdx-video-tutorial?pk_campaign=tt2014cwb
This should still leave an All member:
SELECT
[measures].[sales] ON 0
FROM
(
SELECT
FROM [MyCube]
WHERE
[store].[store].[042]
);
...but the member [All] of the Store hierarchy will only now be made up of [store].[store].[042].
You can see this by adding the Store hierarchy onto ROWS:
SELECT
[measures].[sales] ON 0,
[store].MEMBERS ON 1
FROM
(
SELECT
FROM [MyCube]
WHERE
[store].[store].[042]
);
This is the AdvWorks version similar to the reference in your question:
SELECT
{[Measures].[Order Count]} ON 0
,[Subcategory].MEMBERS ON 1
FROM
(
SELECT
{
[Subcategory].[Subcategory].&[22]
} ON 0
FROM [Adventure Works]
);
It returns the member from the sub-select and the All member adjusted to take account of the subselect:
In the references article why is the [All] less than the sum of the other two - this is not down to the subselect but is in connection with the measure that he has chosen [Measures].[Order Count] which is a distinct count. If you take away the subselect you see exactly the same behaviour of the All member being less than the sum of the other subcategory members (I've marked the point at which the total of the parts becomes higher than the All member):
SELECT
{[Measures].[Order Count]} ON 0
,Order
(
[Subcategory].MEMBERS
,[Measures].[Order Count]
,bdesc
) ON 1
FROM [Adventure Works];
Order Count: on 1 order there might be several Product Subcategories - hence this behaviour.
Edit
This query of yours:
select
[measures].[sales] on 0
from (select
[store].[state].members on 0
from TestCube //<< added this!
where [store].[store].[042]
)
This inner script is not valid? Using the same dimension on an axes and the WHERE clause is not valid:
select
[store].[state].members on 0
from TestCube
where [store].[store].[042]
Edit2
An mdx script returns a cube, which may be sliced or not sliced, but nevertheless it returns a cube. The WHERE clause is used to slice the cube that is returned. If we were using a third party tool then the dimension added to the WHERE clause would go into a combobox - with say Cliffside selected. BUT the user could effectively select Ballard from that combobox - it is just a slicer. The WHERE clause is not changing the cube that is returned by the mdx script, it is just affecting what is displayed in the cellset.
WHERE is valid within a subselect. It is part of the definition:
https://msdn.microsoft.com/en-us/library/ff487138.aspx
I've never found a use case for a subselect's WHERE clause.
Edit3
This link will explain things:
https://social.msdn.microsoft.com/Forums/sqlserver/en-US/ccb66ac3-0f9a-4261-8ccc-b6ecc51b6f07/is-where-clause-pointless-inside-a-subselect?forum=sqlanalysisservices
As Darren gosbell says in the answer to this question:
https://msdn.microsoft.com/en-us/library/ff487138.aspx it says that:
The WHERE clause does not filter the subspace.

MDX show all sales until now

i have a huge table of cashflows that means there are +int values for income and -int values for outcome.
I have MeasureGroup for Sum the amount of money.
I now want to display not only the sum of money per month but also the sum of all the past time until the current month so like that:
Month MoneyAmount Total
1 20 20
2 -10 10
3 5 15
4 -10 5
So i know for the first part its just like
select [Measures].[Money] on 0,
[Date].[Month].Members on 1
From MyCube
but how can i add the sum column?
i thought about something like SUM( { NULL : [Date].[Month].CurrentMember } , [Measures].[Money] ) but that didnt work as well :(
In MDX, the total is already there. You do not have to do complex calculations to get it.
But it depends on your exact hierarchy structure how the All member is called. If you have a date user hierarchy named [Date].[Date], and it has a month level named [Date].[Date].[Month], then the all member of the hierarchy would probably be called something like [Date].[Date].[All]. If [Month] is an attribute hierarchy of the Date dimension, then the "all member" would probably be called [Date].[Month].[All]. In the latter case, the all member would already be the first member of the set [Date].[Month].Members. As you are asking the question, I am assuming this is not the case, and you are using a user hierarchy. Then you could change your MDX query to
select [Measures].[Money] on 0,
Union([Date].[Month].Members, { [Date].[Date].[All] }) on 1
From MyCube
Please note that you can change the name of the All member in the property settings of a dimension when designing an Analysis Services dimension, hence I cannot know the definitive name without knowing the details of this setting in your cube. So you might have to adapt the name of the all member.
You can find this name out in SQL Server Management Studio in an MDX window as follows: open the hierarchy that you are using, and then open the "Members" node, below which you should find the "All Member". You can drag this into your MDX statement, and the proper name will appear there.
As in a running sum?
You need a calculated measure, like this:
With Member [Measures].[Running Sum] as Sum( ( [Date].[Months].Members.Item(0) : [Date].[Months].CurrentMember ), [Measures].[Money])
Select [Date].[Months].Members on Rows,
{[Measures].[Money], [Measures].[Running Sum] } on Columns
From [MyCube]

How filter only the children members in MDX?

When I run this mdx query, works fine (get the children members from a hierarchy level):
select {} on columns,
[Dimension].[hierarchy].[level].children on rows
from [Cube]
But, when I add some tuple on rows, doesn't filter filter the children members (shows all the members) :S
select {} on columns,
[Dimension].[hierarchy].[level].children
* [Dimension2].[hierarchy2].[level2].allmembers on rows
from [Cube]
* is a cross join - you will get the Cartesian product of [Dimension].[hierarchy].[level].children and [Dimension2].[hierarchy2].[level2].allmembers because they are different dimensions.
If they were two hierarchies from the same dimension then auto exist behaviour would limit the results e.g. Year2014 crossed with month should just show the months in 2014.
Try using DESCENDANTS function + you might not require NULLs so try the NON EMPTY
SELECT
{} ON COLUMNS,
NON EMPTY
DESCENDANTS(
[Dimension].[hierarchy].[level].[PickAHigherUpMember],
[Dimension].[hierarchy].[PickTheLevelYouWantToDrillTo]
)
*
[Dimension2].[hierarchy2].[level2].allmembers ON ROWS
FROM [Cube]
if you look at the mdx language reference for children, you will also find another example of how to use the function with a hierarchy in stead of a member_expression.
http://msdn.microsoft.com/en-us/library/ms146018.aspx
but it won't work with a hierarchy level.
Maybe the row expression was initialy a hierarchy that you've have changed into a level expression.
in the following a similar working mdx with a hierarchy on rows:
select {} on 0,
[Product].[Model Name].children
*
[Geography].[Country].[All Geographies]
on 1
FROM [Adventure Works
Philip,
I guess you want only those rows where the children have a value on the default measure. In that case you could try the following:
select {} on columns,
Nonempty([Dimension].[hierarchy].[level].children
* [Dimension2].[hierarchy2].[level2].allmembers) on rows
from [Cube]
Now if, for the children, you'd need all the members from Dimension2 then you could try:
select {} on columns,
Nonempty([Dimension].[hierarchy].[level].children, [Dimension2].[hierarchy2].[level2].allmembers)
* [Dimension2].[hierarchy2].[level2].allmembers) on rows
from [Cube]
In the second case the Nonempty function takes a second parameter and the cross join is done with the result of the Nonempty function. For the documentation on Nonempty including the usage of the second parameter see https://learn.microsoft.com/en-us/sql/mdx/nonempty-mdx

MDX - calculated member with unrelated dimension

I have two measures:
[Measure].[ChildCount] and [Measure].[Buyings]
and two dimensions:
[Buyers] and [Sellers].
[Measure].[ChildCount] uses [Buyers] dimension to count child organization for each of the buyer.
[Measure].[Buyings] uses [Buyers] and [Sellers] to count buying from [Seller] to [Buyer].
What I want to achieve is select all buyings for Buyers with ChildCount < 1 and Buyers with ChildCount > 0.
Currently these queries are working fine:
First one that count buying for each sender/buyer:
SELECT [Measure].[Buyings] on COLUMNS,
[Sellers].[Code].[Code] *
[Buyers].[Code].[Code] ON ROWS
FROM MyCube
And second that calculates buyings for buyers with and without childs:
WITH MEMBER [Measure].[BuyingsWithChilds]
as SUM
(
FILTER([Buyers].[Code].[Code],[Measure].[ChildCount]>0),
[Measure].[Buyings]
)
MEMBER [Measure].[BuyingsWithoutChilds]
as SUM
(
FILTER([Buyers].[Code].[Code],[Measure].[ChildCount]<1),
[Measure].[Buyings]
)
SELECT
{
[Measure].[BuyingsWithChilds],
[Measure].[BuyingsWithoutChilds]
} ON COLUMNS,
[Buyers].[Code].[Code] ON ROWS
FROM MyCube
But if I trying to combine these queries into desired one:
WITH MEMBER [Measure].[BuyingsWithChilds]
as SUM
(
FILTER([Buyers].[Code].[Code],[Measure].[ChildCount]>0),
[Measure].[Buyings]
)
MEMBER [Measure].[BuyingsWithoutChilds]
as SUM
(
FILTER([Buyers].[Code].[Code],[Measure].[ChildCount]<1),
[Measure].[Buyings]
)
SELECT
{
[Measure].[BuyingsWithChilds],
[Measure].[BuyingsWithoutChilds]
} ON COLUMNS,
[Sellers].[Code].[Code] ON ROWS
FROM MyCube
This query's execution takes forever.
Is it possible to fix or optimize this?
If you convert [Measure].[ChildCount]>0 and [Measure].[ChildCount]<1 to an attribute like "HasChildren", then you can avoid the Filter function which is normally slow, and which you use two times.
Then your WITH clause would be simplified to
WITH MEMBER [Measure].[BuyingsWithChilds]
as ([Buyers].[HasChildren].[Yes], [Measure].[Buyings])
MEMBER [Measure].[BuyingsWithoutChilds]
as ([Buyers].[HasChildren].[No], [Measure].[Buyings])
which should be much faster, as it uses the standard aggregation of [Measure].[Buyings].