Exclude a member for MDX forecasting using linear regression - sql-server-2012

I want to forecast measure value for the next month using data from complete previous months.
For example in this moment September 11, I have to forecast the value of the September month (cause the September month is not over) based on January-August values.
I am using MDX function LinRegPoint with the hierarchy detailed below
DimTime
Hierarchy Time
Year
Quarter
Month
This is the query I been trying without success:
WITH
MEMBER [Measures].[Trend] AS
LinRegPoint
(
Rank
(
[Time].[Hierarchy Time].CurrentMember
,[Time].[Hierarchy Time].CurrentMember.Level.MEMBERS
)
,Descendants
(
[Time].[Hierarchy Time].[2015]
,[Time].[Hierarchy Time].CurrentMember.Level
)
,[Measures].[Quality]
,Rank
(
[Time].[Hierarchy Time]
,[Time].[Hierarchy Time].Level.MEMBERS
)
)
SELECT
{
[Measures].[Quality]
,[Measures].[Trend]
} ON COLUMNS
,Descendants
(
[Time].[Hierarchy Time].[2015]
,[Time].[Hierarchy Time].[Month]
) ON ROWS
FROM [Cube];
The above query return all month forecasted values to today date including the September month, however It forecasts the September value taking the real values from January to September current date. I need the LinRegPoint function just takes the previous complete months in this case January to August.
Note the query returns a forecasted value for 9 month (September) but it is using the real value to calculate it. It would result in a misunderstood line as shown in the below images.
This image shows the drawn line taking the previous full-month (1-8):
Note the positive slope line.
This image shows the drawn line taking all months (1-9)
Note the negative slope line.
Question:
How can I exclude the no complete current month from real values but allowing the forecasted value be calculated.
EDIT:
The set should be changing to exclude the last month member in real values but calculating the forecasted value for it.
Thanks for considering my question.
SOLUTION:
WITH MEMBER [Measures].[Trend] AS
LinRegPoint
(
Rank(
[Time].[Hierarchy Time].CurrentMember
,[Time].[Hierarchy Time].CurrentMember.Level.MEMBERS
)
,Descendants
(
[Time].[Hierarchy Time].[2015]
,[Time].[Hierarchy Time].CurrentMember.Level
)
,[Measures].[QltyNoCurrentVal]
,Rank(
[Time].[Hierarchy Time]
,[Time].[Hierarchy Time].Level.MEMBERS)
),FORMAT_STRING='Standard' //Formating
MEMBER [Measures].[QltyNoCurrentVal] AS
IIF(
[Time].[Hierarchy Time].CurrentMember is [Time].[Hierarchy Time].[2015].[3].[9]
, NULL
, [Measures].[Quality]
),FORMAT_STRING='Standard' //Formating
select {
[Measures].[QltyNoCurrentVal]
,[Measures].[Trend]} ON COLUMNS
,Descendants(
[Time].[Hierarchy Time].[2015]
,[Time].[Hierarchy Time].[Month]
) ON ROWS
FROM [Cube]

Slightly confused which sets in your expression need changing.
I've created a set [MthsExclSept] which you should be able to use anywhere in the rest of your script - I've just used it in two places:
WITH
SET [MthsExclSept] AS
SubSet
(
Descendants
(
[Time].[Hierarchy Time].[2015]
,[Time].[Hierarchy Time].[Month] //<<better to specify the month level
)
,0
,
Descendants
(
[Time].[Hierarchy Time].[2015]
,[Time].[Hierarchy Time].[Month] //<<better to specify the month level
).Count
- 1
)
MEMBER [Measures].[Trend] AS
LinRegPoint
(
Rank
(
[Time].[Hierarchy Time].CurrentMember
,[MthsExclSept] //<<also added here?
)
,[MthsExclSept]
,[Measures].[Quality]
,Rank
(
[Time].[Hierarchy Time]
,[MthsExclSept] //<<also added here?
)
)
MEMBER [Measures].[QualityNEW] AS
IIF(
[Time].[Hierarchy Time].CurrentMember is [Time].[Hierarchy Time].[September]
, NULL
, [Measures].[Quality]
)
SELECT
{
[Measures].[QualityNEW]
,[Measures].[Trend]
} ON COLUMNS
,[MthsExclSept] ON ROWS
FROM [Cube];
The set [MthsExclSept] just trims off the last month. Here is a proof via AdvWrks that trims of December from a year:
WITH
SET [MthsExclSept] AS
SubSet
(
Descendants
(
[Date].[Calendar].[Calendar Year].&[2009]
,[Date].[Calendar].[Month]
)
,0
,
Descendants
(
[Date].[Calendar].[Calendar Year].&[2009]
,[Date].[Calendar].[Month]
).Count
- 1
)
SELECT
{} ON 0
,[MthsExclSept] ON 1
FROM [Adventure Works];
It returns the following:

Related

MDX Query to get Last Year data without filtering based on current month

i have been doing a query to get previous year value in MDX but can't the the desired output. In sql i would do it like this. Question is how do i apply this query in MDX?
select data1, sum(data2) as sumthisyear, sumlastyear
from table1 a
left outer join
( select data1, sum(data2) 'sumlastyear'
from table1
where tableyear = 2017 group by data1
) b on a.data1 = b.data1
where tableyear= '2018' and datafilter = 'SampleFilter'
group by data1, sumlastyear
SSAS Cube Structure Image
I have done some research and did mdx function like parallelperiod but not giving the correct values as data are filtered based on 2018 year.
Here's my MDX query
CREATE MEMBER CURRENTCUBE.Measures.[SPLY Registered Sales] AS
iif( [DimProdDate].[Dates].CurrentMember Is
[DimProdDate].[Dates].[All].LastChild,
( PARALLELPERIOD( [DimProdDate].[Dates].[Calendar Year],
1,
Tail( NonEmpty( [DimProdDate].[Dates].[Full Date].MEMBERS,
[MEASURES].[Registered Sales]),
1
).Item(0)
),
[MEASURES].[Registered Sales] ),
( PARALLELPERIOD( [DimProdDate].[Dates].[Calendar Year],
1,
[DimProdDate].[Dates].CurrentMember
),
[MEASURES].[Registered Sales] )
);
Any help will be very much appreciated.
Thanks!

MTD for current month in last year

How I can calculate MTD for current month in last year? Below query returns total [Net Sales Amount] for 12.2015, but need to have sales from 01.12.2015 to 09.12.2015(Today).
SUM(
MTD(
ParallelPeriod(
[Calender].[YMD].[Month],
12,
[Calender].[YMD].CurrentMember
)
)
,[Measures].[Net Sales Amount]
)
I think you need to use HEAD of the member you're finding:
SUM(
HEAD(
ParallelPeriod(
[Calender].[YMD].[Month],
12,
[Calender].[YMD].CurrentMember
).CHILDREN,
, 9
)
,[Measures].[Net Sales Amount]
)
The above is assuming that in the design of your cube Dates are the children of Month.
You need to make the 9 dynamic - do you have future dates in your cube?
If you do not have future dates then this could work:
WITH
MEMBER [Measures].[NumDaysInCurrentMonth] AS
Count(
Descendants(
TAIL([Date].[Calendar].[Month]).Item(0) //<<<not sure if Item(0) is required
,[Date].[Calendar].[Date]
,SELF
)
)
If you do have future dates then maybe the following:
WITH
MEMBER [Measures].[NumDaysInCurrentMonth] AS
count(
NONEMPTY(
Descendants(
TAIL([Date].[Calendar].[Month]).Item(0) //<<<not sure if Item(0) is required
,[Date].[Calendar].[Date]
,SELF
)
)
)
Then one of the above can feed into the previous:
WITH
MEMBER [Measures].[NumDaysInCurrentMonth] AS
COUNT(
Descendants(
TAIL([Date].[Calendar].[Month]).Item(0) //<<<not sure if Item(0) is required
,[Date].[Calendar].[Date]
,SELF
)
)
MEMBER [Measures].[PrevYearMTD] AS
SUM(
HEAD(
ParallelPeriod(
[Calender].[YMD].[Month],
12,
[Calender].[YMD].CurrentMember
).CHILDREN,
, [Measures].[NumDaysInCurrentMonth]
)
,[Measures].[Net Sales Amount]
)

How to query 3 month running average from SSAS Multidimensional Cube (MDX) for each date?

I have SSAS Multidimensional Cube and I need to query 3 month running average for each day in date range.
For example, for 2016-04-25 I must to get data from 2016-01-01 to 2016-03-31.
So I can't use this query (because I don't know how much days I must lag till previous month):
WITH MEMBER [Measures].[SalesAmount 3m average] AS
(
SUM(
([Date].[Date].CurrentMember.Lag(90) :
([Date].[Date].CurrentMember.Lag(1),
[Measures].[SalesAmount]
)
)
I guess I need to use Ancestor function to get month and use lag to month granularity.
Ok, let's try this one:
WITH MEMBER [Measures].[SalesAmount 3m average] AS
(
SUM(
(Ancestor ( [Date].[Date].CurrentMember, [Date].[Month] )).Lag(3) :
(Ancestor ( [Date].[Date].CurrentMember, [Date].[Month] )).Lag(1),
[Measures].[SalesAmount]
)
)
SELECT { [Measures].[SalesAmount 3m average] } ON Columns,
{ [Date].[Date].&[2016-01-01T00:00:00] : [Date].[Date].&[2016-02-28T00:00:00]} On Rows
FROM [Cube]
Unfortunately, this query doesn't work properly (returns null).
How to solve this problem?
UPDATED:
Ok, I tryed to query member caption:
MEMBER [Measures].[Test] AS
(
(Ancestor
( [Date].[Date].CurrentMember,
[Date].[Date].[Month] )
).Item(0).Member_Caption
)
And I'm getting not a Month caption, but a Date(Day) - the same date as [Date].[Date].CurrentMember.
Then I tryed this queries:
--First try
MEMBER [Measures].[Test] AS
(
IsAncestor([Date].[Date].CurrentMember, [Date].[Month].&[2016-05-01T00:00:00])
)
--Second try
MEMBER [Measures].[Test] AS
(
IsAncestor([Date].[Date].CurrentMember, [Date].[Date].[Month].&[2016-05-01T00:00:00])
)
--Third try
MEMBER [Measures].[Test] AS
(
IsAncestor([Date].[Date].CurrentMember, [Date].[Year - Quarter - Month - Date].[Month].&[2016-05-01T00:00:00])
)
In all queries result was "False". So, Month member not an ancestor to Date members??? Now I'm really confused.
My Date dimension looks like this:
UPDATE 2:
MEMBER [Measures].[Test] AS
(
(Ancestor
( [Date].[Date].CurrentMember,
1 )
).Member_Caption
)
Returns: All
Your code seems fine. I'd add item(0) in a couple of places to make things more obvious but this shouldn't change much
WITH
MEMBER [Measures].[SalesAmount 3m average] AS
Sum
(
Ancestor
(
[Date].[Calendar].CurrentMember
,[Date].[Calendar].[Month]
).Item(0).Lag(3)
:
Ancestor
(
[Date].[Calendar].CurrentMember
,[Date].[Calendar].[Month]
).Item(0).Lag(1)
,[Measures].[Internet Sales Amount]
)
SELECT
{[Measures].[SalesAmount 3m average]} ON COLUMNS
,{
[Date].[Calendar].[Date].&[20060222]
:
[Date].[Calendar].[Date].&[20060722]
} ON ROWS
FROM [Adventure Works];
Returns this:
Check that all your level expressions are correct:
[Date].[Date] ?
and
[Date].[Month] ?
Also as a further test what does this return?
WITH
MEMBER [Measures].[test1] AS
Ancestor
(
[Date].[Date].CurrentMember
,[Date].[Month]
).Item(0).Lag(3).Member_Caption
MEMBER [Measures].[test2] AS
Ancestor
(
[Date].[Date].CurrentMember
,[Date].[Month]
).Item(0).Lag(1).Member_Caption
SELECT
{
[Measures].[test1]
,[Measures].[test2]
} ON COLUMNS
,{
[Date].[Date].&[2016-01-01T00:00:00]
:
[Date].[Date].&[2016-02-28T00:00:00]
} ON ROWS
FROM [Cube];
Ancestor will function between different levels of the same hierarchy ie:
What this means is that [Date].[Date] and [Date].[Month] are not really related via Ancestor. Try this:
WITH
MEMBER [Measures].[SalesAmount 3m average] AS
(
SUM(
Ancestor (
[Date].[Year - Quarter - Month - Date].CurrentMember,
[Date].[Year - Quarter - Month - Date].[Month] ).Lag(3)
:
Ancestor(
[Date].[Year - Quarter - Month - Date].CurrentMember
,[Date].[Year - Quarter - Month - Date].[Month] ).Lag(1)
,[Measures].[SalesAmount]
)
)
SELECT
{ [Measures].[SalesAmount 3m average] } ON Columns,
{
[Date].[Year - Quarter - Month - Date].[Date].&[2016-01-01T00:00:00]
: [Date].[Year - Quarter - Month - Date].[Date].&[2016-02-28T00:00:00]
//I suspect the above 2 lines can be replaced by following:
// [Date].[Date].&[2016-01-01T00:00:00]
//: [Date].[Date].&[2016-02-28T00:00:00]
}
On Rows
FROM [Cube];
note
This should return All because the hierarchy [Date].[Date] only has two levels ... the leaf level are the dates with a single level above that All:
MEMBER [Measures].[Test] AS
(
(Ancestor
( [Date].[Date].CurrentMember,
1 )
).Member_Caption
)

Create Set to get Last month of Each Year

I would like to create a set that returned the last Date for each year. For example all previous years would return December, but the current year would only return the current month.
WITH
SET testset AS
NonEmpty
(
Generate
(
{
OpeningPeriod([Date].[Calendar].[Month])
:
ClosingPeriod([Date].[Calendar].Month)
}
,{[Date].[calendar].CurrentMember}
)
,[Measures].[Sale Amount]
)
SELECT
NON EMPTY
(
[Measures].[Sale Amount]
,[Date].[Year].[Year]
) ON 0
,NON EMPTY
[testset] ON 1
FROM [Cube]
Here is an example of a script that returns the values for each month. I've tried using tail and lastchild, but that only returns the most recent. I would like it to return for every Year.
In terms of just the last month - ignoring whether there is data for it or not the following:
WITH
SET [AllYears] AS
[Date].[Calendar].[Calendar Year].MEMBERS
SET [LastMths] AS
Generate
(
[AllYears] AS S
,Tail
(
Descendants
(
S.CurrentMember
,[Date].[Calendar].[Month]
)
,1
)
)
SELECT
{} ON 0
,[LastMths] ON 1
FROM [Adventure Works];
Returns this:
If I want to adapt the above so that it is the last month per year that has data for a specific measure then wrap NonEmpty around the set created by Descendants:
WITH
SET [AllYears] AS
[Date].[Calendar].[Calendar Year].MEMBERS
SET [LastMths] AS
Generate
(
[AllYears] AS S
,Tail
(
NonEmpty //<<new
(
Descendants
(
S.CurrentMember
,[Date].[Calendar].[Month]
)
,[Measures].[Internet Sales Amount] //<<new
)
,1
)
)
SELECT
{} ON 0
,[LastMths] ON 1
FROM [Adventure Works];
It now gives us this:
We can then add in the tuple you have on rows (I have used the attribute hierarchy this time for years as [Date].[Calendar] is already in use)
WITH
SET [AllYears] AS
[Date].[Calendar].[Calendar Year].MEMBERS
SET [LastMths] AS
Generate
(
[AllYears] AS S
,Tail
(
NonEmpty
(
Descendants
(
S.CurrentMember
,[Date].[Calendar].[Month]
)
,[Measures].[Internet Sales Amount]
)
,1
)
)
SELECT
NON EMPTY
(
[Measures].[Internet Sales Amount]
,[Date].[Calendar Year].[Calendar Year]
) ON 0
,[LastMths] ON 1
FROM [Adventure Works];
Now we get this:
#Whytheq has already given a very good solution. Treat this as an alternative. This might be a tad faster as it doesn't use the GENERATE function (not sure though!).
Have a calculated/cube measure which basically tells whether a month is the last month of the year. Then select those months out of the set of months.
with member measures.islastchild as
iif
(
[Date].[Calendar].currentmember is
[Date].[Calendar].currentmember.parent.parent.parent.lastchild.lastchild.lastchild,
1,
null
)
The member measures.islastchild returns 1 if the month is the last month of the year. Else it would return null.
set lastmonths as
filter(
[Date].[Calendar].[Month].members,
measures.islastchild = 1
)
The set lastmonths is then the set you need.
edit
To further improve the performance, you can NonEmpty function instead of the iterative FILTER function.
set lastmonths as
NonEmpty(
[Date].[Calendar].[Month].members,
measures.islastchild
)
select lastmonths on 1,
{} on 0
from [Adventure Works]
EDIT 2: To get the last non month with sales
with member measures.islastnonemptychild as
iif
(
[Date].[Calendar].currentmember is
TAIL(NonEmpty([Date].[Calendar].currentmember.parent.parent.parent.lastchild.lastchild.children, [Measures].[Sale Amount])).ITEM(0),
1,
null
)
set nonemptylastmonths as
NonEmpty(
[Date].[Calendar].[Month].members,
measures.islastnonemptychild
)

MDX return last month of every year

I am trying to create a set to return the value of the last month that contains data for each year.
For example if I would put year on the rows
2011,2012,2013,2014 would all contain data for December.
2015 would contain data for June of 2015.
I can't seem to get anything but the latest month to return. I figure it is because of my tail statement, but I'm not sure how to fix it.
CREATE SET [Last Statement Month] AS
Tail(
nonempty(
Descendants(
[Date].[Calendar].currentmember
,[Date].[Calendar].[Month]
),
[Measures].[Sale Amount]
), 1);
I also tried to get the last day of each month, but when I use this with the year on the rows nothing shows up.
GENERATE(
{
Openingperiod([Date].[Calendar].[Month]):ClosingPeriod([Date].[Calendar].Month)
},
{[Date].[Calendar].CurrentMember.Lastchild}
);
I'm currently away from AdvWrks so unable to test. Does the following help?
CREATE SET [Last Statement Month] AS
TAIL(
NONEMPTY(
EXISTING ([Date].[Calendar].[Month].MEMBERS)
,[Measures].[Sale Amount]
)
);
(If this approach works) Performance is apparently better if EXISTING is performed last:
CREATE SET [Last Statement Month] AS
TAIL(
EXISTING
NONEMPTY(
[Date].[Calendar].[Month].MEMBERS
,[Measures].[Sale Amount]
)
);
Looks like the above isn't going to work. I've added an alternative in the following which maybe is more what you're looking for:
WITH
DYNAMIC SET [Last Statement Month] AS
Tail
(
NonEmpty
(
(EXISTING
[Date].[Calendar].[Month].MEMBERS)
,[Measures].[Internet Sales Amount]
)
)
MEMBER [Measures].[x] AS
[Last Statement Month].Item(0).Item(0).Member_Caption
MEMBER [Measures].[Lst mth with data] AS `<<<<maybe something like this helps?
Max
(
(EXISTING
[Date].[Calendar].[Month].MEMBERS)
,IIF
(
[Measures].[Internet Sales Amount] = 0
,NULL
/*,[Date].[Calendar].CurrentMember.Member_Caption*/ //<<WRONG PROPERTY USED
,[Date].[Calendar].CurrentMember.MemberValue //<<should help!!
)
)
SELECT
{[Measures].[Lst mth with data],[Measures].[x]} ON 0
,[Date].[Calendar].[Calendar Year] ON 1
FROM [Adventure Works];
Results in this:
After Edit returns this: