Does YTD can handle date range ?
I'm trying to compare a period of X days of the current year with the same period of the prior year.
My MDX query looks like this :
WITH MEMBER [Measures].[Prior YTD Amount] AS SUM
(
YTD
(
ParallelPeriod
(
[Date].[Year],
1,
[Date].CurrentMember
)
)
,
[Measures].[Amount]
)
set [ColSet] as
{
[Measures].[Amount],
[Measures].[Prior YTD Amount]
}
set [RowSet] as
{
[Motif].[Categorie].Members
}
SELECT
NON EMPTY [ColSet] ON COLUMNS,
NON EMPTY [RowSet] ON ROWS
FROM [Things]
WHERE
{
[Date].[2015].[2].[1]:[Date].[2015].[2].[9]
}
I'm working with Mondrian 3.6.
In short this code will not work. Reason being that the following line of code is looking for a single member of the hierarchy you've applied the Currentmember to:
[Date].CurrentMember
You have more than one member in the set [Date].[2015].[2].[1]:[Date].[2015].[2].[9]
Here is a small proof of the above:
This script:
WITH
MEMBER [Measures].[x] AS
[Date].[Calendar].CurrentMember.Member_Key
SELECT
{[Product].[Category].[All Products]} ON 0
,{[Measures].[x]} ON 1
FROM [Adventure Works]
WHERE
{
[Date].[Calendar].[Date].&[20080322]
};
Returns this:
Whereas this script:
WITH
MEMBER [Measures].[x] AS
[Date].[Calendar].CurrentMember.Member_Caption
SELECT
{[Product].[Category].[All Products]} ON 0
,{[Measures].[x]} ON 1
FROM [Adventure Works]
WHERE
{
[Date].[Calendar].[Date].&[20080322]
:
[Date].[Calendar].[Date].&[20080323]
};
Returns this:
Error message:
In AdvWrks I just wrote the following which might help, if you can move your target range of dates from the WHERE clause to a named set.
How it works:
1.Finds the first date in your named set via .Item(0).Item(0)
2.Finds the last date in your named set via .Item([myStartDates].Count - 1).Item(0)
3.The uses the two dates found to create a range that is parallel
WITH
SET [myStartDates] AS
{
[Date].[Calendar].[Date].&[20080322]
:
[Date].[Calendar].[Date].&[20080323]
}
SET [parallelToFirst] AS
ParallelPeriod
(
[Date].[Calendar].[Calendar Year]
,1
,[myStartDates].Item(0).Item(0)
)
SET [parallelToLast] AS
ParallelPeriod
(
[Date].[Calendar].[Calendar Year]
,1
,[myStartDates].Item(
[myStartDates].Count - 1).Item(0)
)
SET [Rebuild] AS
[parallelToFirst].Item(0) : [parallelToLast].Item(0)
SELECT
{} ON COLUMNS
,[Rebuild] ON ROWS
FROM [Adventure Works];
Easy enough to then Sum that range and pop it in the date dimension:
WITH
SET [myStartDates] AS
{
[Date].[Calendar].[Date].&[20080322]
:
[Date].[Calendar].[Date].&[20080323]
}
SET [parallelToFirst] AS
ParallelPeriod
(
[Date].[Calendar].[Calendar Year]
,1
,[myStartDates].Item(0).Item(0)
)
SET [parallelToLast] AS
ParallelPeriod
(
[Date].[Calendar].[Calendar Year]
,1
,[myStartDates].Item(
[myStartDates].Count - 1).Item(0)
)
SET [ParallelRange] AS
[parallelToFirst].Item(0) : [parallelToLast].Item(0)
MEMBER [Date].[Calendar].[parallelSum] AS
Sum([ParallelRange])
SELECT
{
[myStartDates]
,[ParallelRange]
,[Date].[Calendar].[parallelSum]
} ON 0
,{
[Measures].[Internet Sales Amount]
,[Measures].[Internet Order Quantity]
} ON 1
FROM [Adventure Works];
Here is the result (just to prove it is doing what we want):
Below is an alternative approach, to using ParallelPeriods function.
I am assuming you have all the dates from prev year in the cube, i.e. there are no missing dates in between or "gaps". If so, you can use the LAG function to hop over to the date 365 days(1 year) back. Also, have the dates from current year initially in a set. That way you can parametrize them easily.
Your final MDX should look somewhat similar to:
with set Dates as
{
[Date].[2015].[2].[1]
:
[Date].[2015].[2].[9]
}//<<This can be also written as
//StrToSet("{[Date]."+ #DateStart + ":" + "[Date]."+ #DateEnd + "}")
//#Date1 and #Date2 being the parameters you can pass from front end
set datesPrevYear as
{
head(Dates, 1).item(0).LAG(365).item(0) \\<<Gets the starting date's 1 year previous date
:
tail(Dates, 1).item(0).LAG(365).item(0) \\<<Gets the ending date's 1 year previous date
}
member [Measures].[Prior YTD Amount] as
sum(datesPrevYear, [Measures].[Amount])
set [ColSet] as
{
[Measures].[Amount],
[Measures].[Prior YTD Amount]
}
set [RowSet] as
{
[Motif].[Categorie].Members
}
select
non empty [ColSet] on columns,
non empty [RowSet] on rows
from [Things]
Related
New to MDX and inherited an application using the following to retrieve the last 7 work days.
Note, the actual dates are generated dynamically.
WHERE ( [DimCalendar].[WorkDayHierarchy].[WorkDate].&[2016-03-25T00:00:00]
: [DimCalendar].[WorkDayHierarchy].[WorkDate].&[2016-03-26T00:00:00].lag(6)
)
I expected it to use the previous 7 work days:
2016-03-17 to 2016-03-25
But instead, it uses future dates
2016-03-25 to latest date in DimCalendar
From what I've read, it's because 2016-03-26 doesn't exist in the hierarchy, so the end range becomes NULL, which explains the future dates...
[WorkDate].&[2016-03-25T00:00:00] : NULL
The problem is the date values are generated dynamically, and I don't know in advance which values exist in the hierarchy. I'm not sure how to construct the MDX date range to get the desired results.
I've tried using <= and FILTER but keep getting conversion errors. With plain SQL this would be easy. I could just write:
WHERE [WorkDate] >= '2016-03-17'
AND [WorkDate] <= '2016-03-25'
Any ideas what the equivalent filter would be in MDX?
A quick fix could be
WHERE ( [DimCalendar].[WorkDayHierarchy].[WorkDate].&[2016-03-25T00:00:00].lag(7)
: [DimCalendar].[WorkDayHierarchy].[WorkDate].&[2016-03-25T00:00:00]
)
But this will only work if the past date is in the hierarchy, which in this case in 2016-03-25.
Edit: Based on the issue below
///Query without using strong names . (no &)
select {[Measures].[Internet Order Count] }
on columns,
[Date].[Day of Year].[1]:[Date].[Day of Year].[10]
on rows
from [Adventure Works]
//This query filters by making the dimension member value, as a measure value.
WITH
MEMBER [Measures].[Data Type] AS
[Date].[Day of Year].CurrentMember.Properties ("Member_Value",TYPED)
select {[Measures].[Internet Order Count] }
on columns,
filter ([Date].[Day of Year].[Day of Year],[Measures].[Data Type]<12)
on rows
from [Adventure Works]
//You can also try the below one
select
{[Measures].[Internet Sales Amount],[Measures].[Reseller Sales Amount]}
on columns,
filter([Date].[Day of Year].[Day of Year],
[Date].[Day of Year].currentmember.Properties ("Member_Value",TYPED)
>12 and [Date].[Day of Year].currentmember.Properties ("Member_Value",TYPED)<20)
on rows
from
[Adventure Works]
Edit
//this might be the exact solution that would work for you
select
{[Measures].[Internet Sales Amount],[Measures].[Reseller Sales Amount]}
on columns,
([Geography].[Country].&[United States]
)
on rows
from
[Adventure Works]
where
filter([Date].[Day of Year].[Day of Year],
[Date].[Day of Year].currentmember.Properties ("Member_Value",TYPED)
>12 and [Date].[Day of Year].currentmember.Properties ("Member_Value",TYPED)<20)
I have a strange problem, that affects only when processing a Calculated Member in OLAP cube, but not when writing MDX query on said cube.
ParallelPeriod function returns correct values when offsetting by 1 year, or 2 half-years, but not on 1 half-year (same for 12 and 6 months)
I want to get data from the previous half-year next to the current measure to do some math with it.
The following MDX query works as expected:
With Member [LastPeriodValue] As
([Measures].[PP E VERT],
ParallelPeriod(
[DIM_TIME].[Half Year].[Half Year]
,1
,[DIM_TIME].[Half Year].CurrentMember
))
Select
NONEMPTY ({
[DIM_TIME].[Half Year].children
}) on 0
, { [Measures].[PP E VERT], [Measures].[LastPeriodValue] } on 1
from [Cube];
However, when I create a calculated member the result is filled with (null) values.
CREATE MEMBER CURRENTCUBE.[Measures].IeprVertibaStub
AS (
[Measures].[PP E VERT],
ParallelPeriod(
[DIM_TIME].[Half Year].[Half Year]
,1
,[DIM_TIME].[Half Year].CurrentMember
)
),
NON_EMPTY_BEHAVIOR = { [PP E VERT] },
VISIBLE = 1;
However if I change the ParallelPeriod function value in calculated member from 1 half-year to 2 half-years everything works as expected.
I tried the same with LAG function and the results are of similar nature. Works on year period, but not on half-year period.
Does anyone have any ideas where to dig for the problem?
I am trying wrap my head around a way to produce the following result from a Mondrian cube.
Sample Values:
Year Month Sales
---- ----- -----
2015 Jan 10
2015 Feb 11
2015 Mar 12
2015 Apr 10
2015 May 11
2015 Jun 12
Jan-Mar 2015 | Apr-Jun 2015
---------------------------------------------------
Sales Sum | 33 | 33
Sales Average | 11 | 11
The current MDX is something like this:
with
member [Date].[JAN-MAR] as Aggregate([Date].[2015].[3].lag(2):[Date].[2015].[3])
member [Date].[APR-JUN] as Aggregate([Date].[2015].[6].lag(2):[Date].[2015].[6])
member [Measures].[Sales Sum] as Sum([Date].CurrentMember, [Measures].[Sales])
member [Measures].[Sales Average] as Avg([Date].CurrentMember, [Measures].[Sales])
select
{[Date].[JAN-MAR],
[Date].[APR-JUN]} on columns,
{[Measures].[Sales Sum],
[Measures].[Sales Average]} on rows
from [Cube]
The question is how can I get a row to specify an aggregate to use for the current column period aggregation?
Update (17 Aug 2018)
I think I have found a solution, before I get into that I think I should give more background into the scenario. We are using Mondrian to provide some financial reports. Due to the complexity of the reports combined with the fact that end users must be able to create them we have created our own mini reporting tool.
One of the most common report types is measures on rows and columns with various date aggregations e.g. Three Month Rolling Average / Financial Year to Date etc all based on a report parameter date selection offset.
The complexity comes in where for the same column they want different rows to aggregate differently. An example would be the Financial Year to Date column, some rows measures must be summed, some must be averaged and some must return the closing balance.
I haven't found an easy want to model this in the cube yet :/
However I found a way to get it to work by mistake that seems relevantly robust and is also fast. As it turns out Mondrian does not validate member attributes, i.e. you can declare and reference whatever member attributes you want. This has turned out to provide an easy way to can get access to the correct date slice and perform whatever aggregate I want e.g:
with
member [Date].[JAN-MAR] as Aggregate([Date].[2015].[3].lag(2):[Date].[2015].[3]), START_MONTH_MEMBER='[Date].[2015].[1]', END_MONTH_MEMBER='[Date].[2015].[3]'
member [Date].[APR-JUN] as Aggregate([Date].[2015].[6].lag(2):[Date].[2015].[6]), START_MONTH_MEMBER='[Date].[2015].[4]', END_MONTH_MEMBER='[Date].[2015].[6]'
member [Measures].[Sales Sum] as Sum([Date].CurrentMember, [Measures].[Sales])
member [Measures].[Sales Average] as Avg(StrToMember([Date].CurrentMember.Properties('START_MONTH_MEMBER')):StrToMember([Date].CurrentMember.Properties('END_MONTH_MEMBER')), [Measures].[Sales])
select
{[Date].[JAN-MAR],
[Date].[APR-JUN]} on columns,
{[Measures].[Sales Sum],
[Measures].[Sales Average]} on rows
from [Cube]
So far this works well. One thing that doesn't work is I cannot get StrToSet to work. In theory you should be able to declare a set in the with member property and then use the in the measure.
StrToMember(([Date].CurrentMember.Properties('MONTH_RANGE_SET'))
So this what I have working for now, would love some feedback on that?
This is a bit time consuming, but should work:
with
member [Date].[JAN-MAR] as Aggregate([Date].[2015].[3].lag(2):[Date].[2015].[3])
member [Date].[APR-JUN] as Aggregate([Date].[2015].[6].lag(2):[Date].[2015].[6])
member [Measures].[Sales Sum] as Sum([Date].CurrentMember, [Measures].[Sales])
member [measures].yearvalues as [Date].currentmember.member_value
member [Measures].[Sales Average] as
AVG
(
StrToSet(
"[Date].[2015].&[" +
CASE
LEFT(measures.yearvalues, 3)
WHEN "JAN" THEN 1
WHEN "APR" THEN 4 END +
"]:[Date].[2015].&[" +
CASE
RIGHT(measures.yearvalues, 3)
WHEN "MAR" THEN 3
WHEN "JUN" THEN 5 END +
"]"
)
,
[Measures].[Sales]
),
format_string = "#.##"
select
{[Date].[JAN-MAR],
[Date].[APR-JUN]} on columns
{[Measures].[Sales Sum],
[Measures].[Sales Average]} on columns
from [Cube]
Far from ideal but best I can do at the moment:
WITH
SET [JAN-MAR] AS
[Date].[Calendar].[Month].&[2006]&[3].Lag(2)
:
[Date].[Calendar].[Month].&[2006]&[3]
SET [APR-JUN] AS
[Date].[Calendar].[Month].&[2006]&[6].Lag(2)
:
[Date].[Calendar].[Month].&[2006]&[6]
MEMBER [Date].[Calendar].[JAN-MAR] AS
Aggregate([JAN-MAR])
MEMBER [Date].[Calendar].[APR-JUN] AS
Aggregate([APR-JUN])
MEMBER [Measures].[Sales Sum] AS
[Measures].[Internet Sales Amount]
MEMBER [Measures].[Sales Average] AS
[Measures].[Internet Sales Amount] / [JAN-MAR].Count
SELECT
{
[Date].[Calendar].[JAN-MAR]
,[Date].[Calendar].[APR-JUN]
} ON 0
,{
[Measures].[Sales Sum]
,[Measures].[Sales Average]
} ON 1
FROM [Adventure Works];
So I thought maybe I'd try adding the custom members to an unrelated dimension (effectively make it a utility dimension). This works ok but extracting the count of number of related months is still proving difficult. This is the current effort:
WITH
SET [JAN-MAR] AS
[Date].[Calendar].[Month].&[2006]&[3].Lag(2)
:
[Date].[Calendar].[Month].&[2006]&[3]
SET [APR-JUN] AS
[Date].[Calendar].[Month].&[2006]&[6].Lag(2)
:
[Date].[Calendar].[Month].&[2006]&[6]
MEMBER [Product].[Category].[JAN-MAR] AS
Aggregate
(
[JAN-MAR]
,[Product].[Category].[All Products]
)
MEMBER [Product].[Category].[APR-JUN] AS
Aggregate
(
[APR-JUN]
,[Product].[Category].[All Products]
)
MEMBER [Measures].[Sales Sum] AS
[Measures].[Internet Sales Amount]
MEMBER [Measures].[Sales Avg] AS
[Measures].[Internet Sales Amount]
/
NonEmpty
(
[Date].[Calendar].[Month].MEMBERS
,(
[Product].[Category].CurrentMember
,[Measures].[Internet Sales Amount]
)
).Count //<<<<currently returning 72 rather than 3
SELECT
{
[Product].[Category].[JAN-MAR]
,[Product].[Category].[APR-JUN]
} ON 0
,{
[Measures].[Sales Sum]
,[Measures].[Sales Avg]
} ON 1
FROM [Adventure Works];
We can see that it is getting divided by 72 rather than 3:
Problem as I currently see it is trying to get hold of the number of related months to each of the custom members after they have been aggregated - here is a simplified example of what I mean:
WITH
SET [JAN-MAR] AS
//<< set of 3 months
[Date].[Calendar].[Month].&[2006]&[1]
:
[Date].[Calendar].[Month].&[2006]&[3]
MEMBER [Product].[Category].[JAN-MAR] AS
//<< chuck on unconnected hierarchy
Aggregate
(
[JAN-MAR]
,[Product].[Category].[All Products]
)
MEMBER [Measures].[countMonthsRelatedToMember] AS //<<attempt to count mths related to [Product].[Category].[JAN-MAR]
NonEmpty
(
[Date].[Calendar].[Month].MEMBERS
,(
[Product].[Category].CurrentMember
,[Measures].[Internet Sales Amount]
)
).Count //<<<<currently returning 72 rather than 3
SELECT
[Product].[Category].[JAN-MAR] ON 0
,[Measures].[countMonthsRelatedToMember] ON 1
FROM [Adventure Works];
I am trying to calculate running totals for a date range which is passed through parameters in SSRS. I know i need to use lag function, but i am not able to get it right. I tried using the following
WITH MEMBER [Measures].[Rolling12Months] AS
SUM(
[Reporting Period].[Fiscal].[Fiscal Month Name].&[1]&[2013] : [Reporting Period].[Fiscal].CURRENTMEMBER,
[Measures].[Amount]
)
Below script will do what #whytheq's script does, only dynamically. It figures out the last 12 months based on the current member, which you can pass on as a slicer, or when you are in a set context, you might not need the slicer axis. I am assuming that's why you thought you needed the LAG function.
WITH SET Last12Months AS
{[Reporting Period].[Fiscal].CURRENTMEMBER.LAG(12) : [Reporting Period].[Fiscal].CURRENTMEMBER}
MEMBER [Measures].[Rolling12Months] AS
SUM(
Last12Months,
[Measures].[Amount]
)
SELECT
[Measures].[Rolling12Months] ON 0
, [Reporting Period].[Fiscal].[Fiscal Month Name].Members ON 1
FROM [YourCubeName]
WHERE [Reporting Period].[Fiscal].[Fiscal Month Name].&[1]&[2014]
//`WHERE` clause can be left out if context is already set.
Your script looks ok - maybe just change to Aggregate:
WITH MEMBER [Measures].[Rolling12Months] AS
Aggregate(
[Reporting Period].[Fiscal].[Fiscal Month Name].&[1]&[2013]:[Reporting Period].[Fiscal].CurrentMember,
[Measures].[Amount]
)
So a complete script would be something like
WITH MEMBER [Measures].[Rolling12Months] AS
Aggregate(
[Reporting Period].[Fiscal].[Fiscal Month Name].&[1]&[2013]:[Reporting Period].[Fiscal].CurrentMember,
[Measures].[Amount]
)
SELECT
{[Measures].[Amount]
, [Measures].[Rolling12Months] } ON 0
, [Reporting Period].[Fiscal].[Fiscal Month Name].Members ON 1
FROM [YourCubeName]
I am trying to retrieve month from parametrized date , by using :
vba!month(${parDate}) or
vba!datePart(m,${parDate}) or
vba!format(${parDate},'mmm')
None of the above is working.Can you guide, what is the right approach to do this?
(try uppercase 'MM' rather than 'mmm' - even 'mm' is wrong as it will look for minutes rather than months)
This question and answer looks at working with dates:
Changing a date format to a shorter date
MSDN is a good reference for the available vba functions in mdx that you can use to play around with dates. Current link is here:
http://msdn.microsoft.com/en-us/library/hh510163.aspx
I'm assuming you have a date dimension and would like to create a calculated measure that returns a numeric value that is the month.
Using AdWks I can do the following:
WITH
MEMBER [Measures].[DateValue] AS
[Date].[Calendar].CurrentMember.MemberValue
MEMBER [Measures].[DateKey] AS
[Date].[Calendar].CurrentMember.Member_Key
MEMBER [Measures].[DateMONTH] AS
Mid
(
[Measures].[DateKey]
,5
,2
)
SELECT
{
[Measures].[DateValue]
,[Measures].[DateKey]
,[Measures].[DateMONTH]
} ON 0
,Order
(
{
Exists
(
[Date].[Date].MEMBERS
,[Date].[Calendar Year].&[2010]
)
}
,[Date].[Calendar].CurrentMember.MemberValue
,BDESC
) ON 1
FROM [Adventure Works];
But maybe you'd just like to play around with today's date and extract the month:
WITH
MEMBER [Measures].[DateValue] AS
[Date].[Calendar].CurrentMember.MemberValue
MEMBER [Measures].[TodayKey] AS
format(Now(),'yyyMMdd')
MEMBER [Measures].[TodayMONTH] AS
Mid
(
[Measures].[TodayKey]
,5
,2
)
SELECT
{
[Measures].[DateValue]
,[Measures].[TodayKey]
,[Measures].[TodayMONTH]
} ON 0
,Order
(
{
Exists
(
[Date].[Date].MEMBERS
,[Date].[Calendar Year].&[2010]
)
}
,[Date].[Calendar].CurrentMember.MemberValue
,BDESC
) ON 1
FROM [Adventure Works];