This might be a longshot, but maybe there is an ssas/mdx guru here that has stumpled upon the same problem regarding aggregated calculations and leap years. So what I am trying to do, is to create a PY YTD calculated measure in an ssas cube that can handle leap years. The issue I am facing is that the calculated measure becomes extremely slow based on the logic below (see code sample). Has anyone found a better way to handle leap years or has a document with best practise to share ? I am assume that if-statements and NonEmpty function could be performance deadly for a calculated measure. All tips are greatly appreciated (Doesn't have to be a solution).
-- YTD PRIOR YEAR
[Time Calculations].[YTD Pr Yr] = IIF([Calendar].[Year - Month - Day].CurrentMember IS [Calendar].[Year - Month - Day].[Month].&[201702]
,Aggregate(
NonEmptyCrossjoin({[Time Calculations].[Current Period]},
PeriodsToDate(
[Calendar].[Year - Month - Day].[Year],
[Calendar].[Year - Month - Day].[Day].&[2016-02-29 00:00:00.000])
))
,IIF([Calendar].[Year - Month - Day].CurrentMember IS [Calendar].[Year - Month - Day].[Month].&[201602]
,Aggregate(
NonEmptyCrossjoin({[Time Calculations].[Current Period]},
PeriodsToDate(
[Calendar].[Year - Month - Day].[Year],
[Calendar].[Year - Month - Day].[Day].&[2015-02-28 00:00:00.000])
))
,(Aggregate(
NonEmptyCrossjoin({[Time Calculations].[Current Period]},
PeriodsToDate(
[Calendar].[Year - Month - Day].[Year],
ParallelPeriod(
[Calendar].[Year - Month - Day].[Year],1,
TAIL(DESCENDANTS([Calendar].[Year - Month - Day].CurrentMember
, [Calendar].[Year - Month - Day].[Day]),1).ITEM(0)))
)
)
)
)
);
Best regards,
Rubrix
Try the following, some caveats follow:
CREATE MEMBER CURRENTCUBE.[Time Calculations].[YTD Prior Year] AS NULL;
/* Make sure the scope is for all days in all years in your calendar year */
Scope([Invoice Date].[Calendar Year].[Calendar Year].members, [Invoice Date].[Calendar Day].members);
// YTD PRIOR YEAR
([Time Calculations].[YTD Prior Year] =
iif(
/* Check to see if the prior year member is empty */
isempty(
ParallelPeriod(
[Invoice Date].[CY Hierarchy].[Calendar Year],
1,
[Invoice Date].[CY Hierarchy].CurrentMember
).MemberValue
),
/* If so, use the .LastChild */
Aggregate(
Crossjoin(
{[Time Calculations].[Current Period]},
PeriodsToDate(
[Invoice Date].[CY Hierarchy].[Calendar Year],
ParallelPeriod(
[Invoice Date].[CY Hierarchy].[Calendar Year],
1,
Ancestor(
[Invoice Date].[CY Hierarchy].CurrentMember,
[Invoice Date].[CY Hierarchy].[Calendar Month]
)
).LastChild
)
)
),
/* Otherwise just use the prior year */
Aggregate(
Crossjoin(
{[Time Calculations].[Current Period]},
PeriodsToDate(
[Invoice Date].[CY Hierarchy].[Calendar Year],
ParallelPeriod(
[Invoice Date].[CY Hierarchy].[Calendar Year],
1,
[Invoice Date].[CY Hierarchy].CurrentMember
)
)
)
)
)
);
End Scope;
One possible hitch is that if you have several days in a row where there are no transactions, .LastChild might not work accurately. I didn't have that situation when I originally developed this code. It was specifically developed to deal with this exact case of prior year-to-date and leap year nuances. It might need to be tweaked if that's the case.
This assumes that you have a proper time dimension and a time calculations dimension, which it looks like you do from the code sample you provided.
I would say that the performance of this solution is pretty great even on large cubes (hundreds of millions of rows).
Related
I have hierarchy: Month,Monthshort and Year-Quarter-Month under TimeDim Dimension,a scope is available like below to calculate YearToDate(YTD)
Scope([TimeDim].[Year - Quarter - Month].[Month].members, [TimeDim].[Month].Members);
YTD:
([TimeDim].[YTD]=
Sum(
CrossJoin(
{[Time Calculation].[Current Period]},
PeriodsToDate([TimeDim].[Year - Quarter - Month].[Year],
[Timedim].[Year - Quarter - Month].CurrentMember
)
)
)
);
Month will be in format YYYY-MM fullname(eg: 2017-10 October) and Month short will be MMM(Oct). If I calculate YTD on the measure based on month it works fine,
How to calculate YTD based on Month Short? Do I require to create new scope to calulate YTD based on Month short? I am new to SSAS. Please help
Yes, this requires new SCOPE.
Because current scope contains Year "anchor" here: [TimeDim].[Year - Quarter - Month].[Year].
Answer will be updated once all additional questions answered
I created below scope for YTD with month short. Thus solved the problem.
Scope([Time Year Month].[Year].members,[Time Year Month].[Year - Month].[Month Short].members);
-- accumulated YTD CALCULATIONS
([Time Calculation].[YTD]=
SUM(
CrossJoin(
{[Time Calculation].[Current Period]},
PeriodsToDate([Time Year Month].[Year - Month].[Year]
)
)
)
);
End Scope;
I'm having issues trying to create a MDX calculated member inside a SSAS cube, that will show the aggregation for the previous 12 months (excluding the current month), based on a date from Calendar hierarchy.
I have found this post, however, because in my case the base measure is a DistinctCount aggregation, the YTD() function does not work by adding Aggregate() - it always displays NULL - and by adding Sum() it will display a RollingSum, which is incorrect.
This is against a DISTINCT COUNT measure and functions ok - although it is understandably slow:
WITH
MEMBER [Measures].[ytdCalc] AS
Aggregate
(
Head
(
Descendants
(
Ancestor
(
[Date].[Date - Calendar Month].CurrentMember
,[Date].[Date - Calendar Month].[Calendar Year]
).Item(0).Item(0)
,[Date].[Date - Calendar Month].[Calendar Month]
)
).Item(0).Item(0)
:
[Date].[Date - Calendar Month].CurrentMember
,[Measures].[Num People]
)
SELECT
{
[Measures].[ytdCalc]
,[Measures].[Num People]
} ON 0
,[Date].[Date - Calendar Month].[Calendar Month] ON 1
FROM [aCube];
YTD works fine for me. I have used it like this:
WITH
MEMBER [Measures].[ytdCalc] AS
Aggregate
(
YTD([Date].[Date - Calendar Month].CurrentMember)
,[Measures].[Num People]
)
SELECT
{
[Measures].[ytdCalc]
,[Measures].[Num People]
} ON 0
,[Date].[Date - Calendar Month].[Calendar Month] ON 1
FROM [aCube];
I am trying to convert some T-SQL queries into MDX:
I require the first date of the Current Quarter for our reporting solution.
Within the cube we have a dynamic 'Current Quarter' flag
This seems like a simple problem but it has caused me no end of issues. I've managed to isolate the correct date but with the query below but in SSRS I get an error that states 'The default value for StartDate is not the expected type' i.e. it is not in DateTime format. This leads me to believe it is being passed as a string
How do I modify the following query to pass the StartDate as a DateTime and not a string?
The second piece of code is a secondary attempt at the same thing except I get the first value of the entire Date dimension (1900-01-01) instead of the first day of the current quarter.
First attempt:
SELECT
NON EMPTY
{} ON COLUMNS,
HEAD(
[Date Lead Date].[Calendar Date].[Calendar Date]
,1) ON ROWS
FROM [Leads]
WHERE [Date Lead Date].[Current Quarter Flag].&[1]
Second attempt (produces 1900-01-01):
WITH
Member [Measures].[StartDate] AS
HEAD(
[Date Lead Date].[Calendar Date].[Calendar Date]
,1).ITEM(0).ITEM(0).NAME
SELECT
NON EMPTY
[Measures].[StartDate] ON COLUMNS
FROM [Leads]
WHERE [Date Lead Date].[Current Quarter Flag].&[1]
Untested but I'm wondering if this works?
WITH
Member [Measures].[StartDate] AS
[Date Lead Date].[Calendar Date].CURRENTMEMBER.MEMBER_VALUE
SELECT
NON EMPTY
{[Measures].[StartDate]} ON COLUMNS,
HEAD(
[Date Lead Date].[Calendar Date].[Calendar Date]
,1) ON ROWS
FROM [Leads]
WHERE [Date Lead Date].[Current Quarter Flag].&[1]
I need to create a calculated member that calculates revenue for TTM (Trailing Twelve Months) associated to selected date (day level).
I tried something like this:
SUM(
{
[Accounting Effective Date].[Date Hierarchy].CurrentMember.Lag(365)
: [Accounting Effective Date].[Date Hierarchy].CurrentMember
},
[Measures].[Revenue]
)
But this doesn't work with leap year, for example if I pick 2013-01-01 than it returns 2012-01-02.
I have also tried this but this one is also not good since it takes first day of the month:
SUM(
{
[Accounting Effective Date].[Date Hierarchy].CurrentMember.Parent.Lag(12).FirstChild
: [Accounting Effective Date].[Date Hierarchy].CurrentMember
},
[Measures].[Revenue]
)
Date hierarhy is following:
Year > Quarter > Month > Date
the following query can help, it uses cousin function to return last years date.
with member [Measures].[TestValue] as
(cousin([Date].[Calendar].currentmember,[Date].[Calendar].currentmember.parent.parent.lag(1)),[Measures].[Internet Sales Amount])
member [Measures].[TestDate] as
cousin([Date].[Calendar].currentmember,[Date].[Calendar].currentmember.parent.parent.lag(1)).item(0).name
select
{[Measures].[Internet Sales Amount],[Measures].[TestValue],[Measures].[TestDate]}
on columns,
{
[Date].[Calendar].[Date].&[20130922]
}
on rows from
[adventure works]
I am new to MDX,
I have a requirement, which is using the measure on that Saturday as the default of that week, I have a time dimension [CALENDAR],
but there are multiple hierachies, different hierachies have different week start, that means in [CALENDAR].[h1].[DATE], the week start may be Thursday(weekday in nature calendar), in the other may be Sunday(in nature calendar),
so I have to using [CALENDAR].[DATE], which is nature calendar, I can get the corresponding Saturday,
with member measures.[Weekday]
as datepart('w',[CALENDAR].[Fiscal].currentmember)
member measures.[SatDay]
as dateadd('d'
,7-datepart('w',[CALENDAR].[Fiscal].currentmember.MemberValue)
,[CALENDAR].[Fiscal].currentmember.MemberValue)
select
{
[Measures].[Plan Count]
,measures.[Weekday]
,measures.[SatDay]
} on 0,
[CALENDAR].[Fiscal].[Date] on 1
from [MyCube]
but how can I the measure on that day?
Try a sub-select using your date hierarchy containing week (Year-Week-Date).
with member [Measures].[WeekDate] as
dateadd('d' ,7 - datepart('w',[Dim Date].[Year - Week - Date].currentmember.MemberValue)
,[Dim Date].[Year - Week - Date].currentmember.MemberValue)
select {[Measures].[WeekDate], [Measures].[Plan Count]} on 0,
[Dim Date].[Year - Week - Date].Children on 1
from (
select ([Dim Date].[Year - Week - Date].[Week]) on 0
from [cube]
where (
//filters if necessary
)
)