In order to give a nicer Cube browsing experience to end users, I am trying to create a Time Periods hierarchy consisting of Calculated Members.
Currently I have used a Calculated Column in my DSV to create a column with the same value on every row in my Dates table (value is All Time). Then within my Date and Time dimension I have created a single level, single member hierarchy using that Calculated Column, which looks like this:
Now what I have already successfully done is add Time Periods to my Calendar hierarchy with the following calculation:
CREATE MEMBER CURRENTCUBE.[Completion Date].[Calendar].[All].[Last 30 Days]
AS SUM(LastPeriods(30,StrToMember(
"[Completion Date].[Calendar].[Day]."+
"&["+CStr(Year(Now()))+"]&["+CStr(Month(Now()))+"]&["+CStr(Day(Now()))+"]"
))),VISIBLE = 1;
This works as expected on the Calendar hierarchy:
But I want to move these into the new Time Periods hierarchy to keep them nicely separated.
So far I have tried to do this in two different ways:
Changing the destination Hierarchy of the Computed Member. Changing CREATE MEMBER CURRENTCUBE.[Completion Date].[Calendar].[All].[Last 30 Days] to CREATE MEMBER CURRENTCUBE.[Completion Date].[Time Period].[All].[Last 30 Days].
Changing the Visibility of the Calculated Member on the Calendar hierarchy to VISIBLE = 0 and creating a second Caculated Member on the Time Periods hierarchy which references it: (I have tried with and without using the SUM() function)
CREATE MEMBER CURRENTCUBE.[Completion Date].[Time Period].[All].[Last 30 Days]
AS SUM([Completion Date].[Calendar].[All].[Last 30 Days]),
VISIBLE = 1;
But neither of these have worked for me. So my question is, How can I complete what I am trying to achieve?
My end goal is to have a Hierarchy which the user can drag into a pivot table and see the following (but with the Time Periods actually calculated):
I've just created the same this way:
1) Add dummy attribute for unfiltered values with the name 'All Time'
(key is int with 0 value)
2) Add 3 empty members
CREATE MEMBER CURRENTCUBE.[Report Date].[Time Period].[All].[Last 30 Days]
AS
null,
VISIBLE = 1;
CREATE MEMBER CURRENTCUBE.[Report Date].[Time Period].[All].[Last 60 Days]
AS
null,
VISIBLE = 1;
CREATE MEMBER CURRENTCUBE.[Report Date].[Time Period].[All].[Last 90 Days]
AS
null,
VISIBLE = 1;
3) Than add scopes (I have another key format):
/* SCOPES */
SCOPE ([Report Date].[Time Period].[All].[Last 30 Days]);
THIS = Sum(LastPeriods(30,StrToMember("[Report Date].[Report Date].[Day].&["+CStr(Format(Now(),"yyyyMMdd"))+"]")));
END SCOPE;
SCOPE ([Report Date].[Time Period].[All].[Last 60 Days]);
THIS = Sum(LastPeriods(60,StrToMember("[Report Date].[Report Date].[Day].&["+CStr(Format(Now(),"yyyyMMdd"))+"]")));
END SCOPE;
SCOPE ([Report Date].[Time Period].[All].[Last 90 Days]);
THIS = Sum(LastPeriods(90,StrToMember("[Report Date].[Report Date].[Day].&["+CStr(Format(Now(),"yyyyMMdd"))+"]")));
END SCOPE;
It works (also add a measure to count members of a level to validate):
Thanks to Alex Peshik's Answer I have managed to get this to work.
Here is the method I have now used to setup a Calculated Time Periods Hierarchy:
Go into your DSV and create a New Named Calculation on your Date table with a name like TimePeriod and set the Value to be something like All Time.
Within your Date dimension create a new Attribute from that Named Calculation and use it to make a Hierarchy.
Make sure the New Attribute is linked to your Day Attribute in the Attribute Relationships tab.
Within your cube, go to the Calculations tab and create a Dummy Calculated Member in the Time Period hierarchy we have made for each time period you want to add:
CREATE MEMBER CURRENTCUBE.[Completion Date].[Time Period].[All].[Last 30 Days]
AS NULL, VISIBLE = 1;
CREATE MEMBER CURRENTCUBE.[Completion Date].[Time Period].[All].[Last 60 Days]
AS NULL, VISIBLE = 1;
CREATE MEMBER CURRENTCUBE.[Completion Date].[Time Period].[All].[Last 90 Days]
AS NULL, VISIBLE = 1;
// etc...
Now at the bottom of your Calculation you add a Scope for each Dummy Calculation we made in the last step (you will need to change the bit within the StrToMember() function to match your day attribute Key):
SCOPE ([Completion Date].[Time Period].[All].[Last 30 Days]);
THIS = SUM(LastPeriods(30, StrToMember(
"[Completion Date].[Calendar].[Day]."+
"&["+CStr(Year(Now()))+"]&["+CStr(Month(Now()))+"]&["+CStr(Day(Now()))+"]"
)));
END SCOPE;
SCOPE ([Completion Date].[Time Period].[All].[Last 60 Days]);
THIS = SUM(LastPeriods(60, StrToMember(
"[Completion Date].[Calendar].[Day]."+
"&["+CStr(Year(Now()))+"]&["+CStr(Month(Now()))+"]&["+CStr(Day(Now()))+"]"
)));
END SCOPE;
SCOPE ([Completion Date].[Time Period].[All].[Last 90 Days]);
THIS = SUM(LastPeriods(90, StrToMember(
"[Completion Date].[Calendar].[Day]."+
"&["+CStr(Year(Now()))+"]&["+CStr(Month(Now()))+"]&["+CStr(Day(Now()))+"]"
)));
END SCOPE;
Related
I am trying to apply a measure value calculated at the Month level to a dimension contained within that month i.e.
Should look like this:
I've attempted to use a scoping statement so far but with no luck.
SCOPE (
{[Sale].[Sale Year].&[2]:[Sale].[Sale Year].&[7]}
,[Date].[Calendar Month].&[201603]
,[Measures].[Costs Per Sale] );
THIS = ([Date].[Calendar Month].&[201603],[Measures].[Costs Per Sale]);
END SCOPE;
The Aggregated Sales measure is calculated using the Sale Year which unfortunately has not and cannot be linked to the Cost dimension.
Does anyone know how I can apply the Cost Per Sale monthly value to the [Sale].[Sale Year] dimension?
Thanks
Try this -
SCOPE ({[Sale].[Sale Year].&[2]:[Sale].[Sale Year].&[7]} ,[Measures].[Costs Per Sale]);
THIS = ([Sale].[Sale Year].[All],[Measures].[Costs Per Sale]);
END SCOPE;
Situation:
I have created calcalated measures in a SQL Server 2012 SSAS multi dimensional model by creating empty measures in the cube and use scope statements to fill the calculation.
(so I can use measure security on calculations as explained here)
SCOPE [Measures].[C];
THIS = IIF([B]=0,0,[Measures].[A]/[Measures].[B]);
I also made a time calculations which I scope for the whole measure group including the calculation above. (as explained here)
I create empty members for the calculations:
--YTD Calculations
CREATE MEMBER CURRENTCUBE.[Calender Calculations].[YTD-1] AS NULL;
CREATE MEMBER CURRENTCUBE.[Calender Calculations].[YTD] AS NULL;
-- MOVING ANNUAL TOTAL Calculations
CREATE MEMBER CURRENTCUBE.[Calender Calculations].[MAT-1] AS NULL;
CREATE MEMBER CURRENTCUBE.[Calender Calculations].[MAT] AS NULL;
--SCOPE MEASUREGROUPMEASURES
I scope the measuregroup on which the calculations will be performed:
SCOPE (MeasureGroupMeasures("Sales")
);
Next I scope the time calculations for the different Time Hierarchys:
SCOPE ([Calender].[Jaar].[Jaar].members,[Calender].[Calender ID].members);
--YTD
([Calender Calculations].[YTD]=
Aggregate(
CrossJoin({[Calender Calculations].[Current Period]},
PeriodsToDate(
[Calender].[Month Hierarchy].[Jaar],
[Calender].[Month Hierarchy].CurrentMember))
)
);
--YTD -1
([Calender Calculations].[YTD-1]=
Aggregate(
Crossjoin({[Calender Calculations].[Current Period]},
PeriodsToDate(
[Calender].[Month Hierarchy].[Jaar],
ParallelPeriod(
[Calender].[Month Hierarchy].[Jaar],1,
[Calender].[Month Hierarchy].CurrentMember))
)
));
--MAT
([Calender Calculations].[MAT]=
Aggregate(
CrossJoin({[Calender Calculations].&[Current Period]},
ParallelPeriod([Calender].[Month Hierarchy].[Month],11,[Calender].[Month Hierarchy].CurrentMember) :
[Calender].[Month Hierarchy].CurrentMember
)));
--MAT-1
([Calender Calculations].[MAT-1]=
Aggregate(
CrossJoin({[Calender Calculations].&[Current Period]},
ParallelPeriod([Calender].[Month Hierarchy].[Month],23,[Calender]. [Month Hierarchy].CurrentMember) :
ParallelPeriod([Calender].[Month Hierarchy].[Month],12,[Calender].[Month Hierarchy].CurrentMember)
)));
--SCOPE Calendar END
END SCOPE;
Close the measuregroup Scope
--SCOPE MEASUREGROUPMEASURES END
END SCOPE;
Results:
When I query the cube by using a ‘base measures’ and the ‘calculated measure’ the results for the time calculations are correct for the base measure but incorrect for the ‘calculated measure’ C because the measure first gets calculated and after that the time calculation is being done, resulting in aggregating the results.
Example:
The current month is April 2015
Every month has a score of 5%.
The YTD measure gives 20% (5% for jan, feb etc.) Which has to be 5%
My question:
How can I change the time calculation or the ‘calculated measure’ so I get the right results?
I want to create a calculated member. I have a time dimension hierarchy" YQM", which has Year/Quarter/Month. The calculated member should find YTD till the current month. However, the value of current month will come from database.
I have created a attribute, "CP" which returns the current month value.
Please tell me how to create the calculated member. Please note "CP" is not in the same hierarchy YQM.
I don't understand why you are using Aggregate. So, I will assume that it is there for some purpose, which you have't clarified. Now, if the members of [YQM].[Month] and [Dim].[CP] are of the same format, then you can try the code below:
Aggregate(
PeriodsToDate([Dim].[YQM].[Month].MEMBERS,
FILTER([Dim].[YQM].[Month].MEMBERS,
[YQM].[Month].CURRENTMEMBER.member_value = [Dim].[CP].FirstChild.member_value)
)
)
Why not try playing with the function YTD. The following should give you the monthly amount in the first column of data and then the YTD amount in the next column:
WITH MEMBER [Measures].[YearToDate] AS
AGGREGATE(
YTD()
,[Measures].[someMeasureInCube]
)
SELECT
{
[Measures].[someMeasureInCube],
[Measures].[YearToDate]
} ON 0,
[Dim].[YQM].[Month].MEMBERS ON 1
FROM [yourCube]
Trying to figure out what the default member adds to this scipt
([DateTool].[Aggregation].[Previous Month]) =
iif(
([DateTool].[Aggregation].DefaultMember, ParallelPeriod(dim_RPT_period].[Yr-Qtr-Month].[RPT Period Month],1,[dim_RPT_period].[Yr-Qtr-Month].currentmember)) = null,
NULL,
([DateTool].[Aggregation].DefaultMember,ParallelPeriod([dim_RPT_period].[Yr-Qtr-Month].[RPT Period Month],1,[dim_RPT_period].[Yr-Qtr-Month].currentmember))
);
This is from a utility dimension. Calculation script.
I get the IIF, and I get the ParallelPeriod.
But what effect does "(DefaultMember, ParallelPeriod)" have?
It looks like it used to avoid infinite recursion. This technique is used in this kind of dynamic calculations.
Let's say we run some MDX script with WHERE [DateTool].[Aggregation].[Previous Month].
Server takes this calculation from your formula (without [DateTool].[Aggregation].DefaultMember), it uses ParallelPeriod as usual, but than it needs [DateTool].[Aggregation].[Previous Month] as a part of tuple with other dimensions (our WHERE filter), so it takes from this formula again and again...
So we always need to have some fixed member to avoid infinite recursion.
That is my understanding, please correct if it's somewhere or totally wrong.
My understanding is that the calculated member is built to have values only when the slicer has any member from [dim_RPT_period].[Yr-Qtr-Month].[RPT Period Month] level. This is my opinion imitates the ISCROSSFILTERED functionality of DAX.
The member is built such that [DateTool].[Aggregation].[Previous Month] would hold value only when
the slicer has a member from [dim_RPT_period].[Yr-Qtr-Month].[RPT Period Month]
[DateTool].[Aggregation].DefaultMember is as good as [DateTool].[Aggregation].[ALL]
It is as good as leaving out [DateTool].[Aggregation] hierarchy from the query
If slicer does not have a member from [dim_RPT_period].[Yr-Qtr-Month].[RPT Period Month],
then [dim_RPT_period].[Yr-Qtr-Month].currentmember is as good as [dim_RPT_period].[Yr-Qtr-Month].[ALL]
The previous member in this case(which is returned by ParallelPeriod function) is undefined and hence, NULL would be returned.
If slicer has the member, a non null member would be returned.
To further illustrate upon this:
(Please read through the comments)
([DateTool].[Aggregation].[Previous Month]) =
iif(
(
[DateTool].[Aggregation].[ALL],
ParallelPeriod([dim_RPT_period].[Yr-Qtr-Month].[RPT Period Month],1,[dim_RPT_period].[Yr-Qtr-Month].currentmember)
) //If a member from dim_RPT_period].[Yr-Qtr-Month].[RPT Period Month] level is not in slicer then it would evaluate to NULL
= null,
NULL, //In that case the previous month should evaluate to NULL
//Otherwise, it should give the "previous month"
([DateTool].[Aggregation].[ALL],
ParallelPeriod([dim_RPT_period].[Yr-Qtr-Month].[RPT Period Month],1,[dim_RPT_period].[Yr-Qtr-Month].currentmember))
);
I have a "Trend" dimension. The hierarchy is, Trend->Week->Day. The fact is linked to the "Day" key. There is no guarantee that measure value will exist for all days in a given week.
When the user wants to see the measure at "Week" level, I need to show only the last empty day value for that Week. I have multiple measures and hence I ain't interested in creating a new calculated measure for each one of them (like How to display the total of a level as the value of its last child in MDX)
Instead, is there any way to create a named set with which I can achieve the functionality as below?
Example
Week Day Measure
1 1 4
1 2 5
2 3 7
2 7 9
3 5 10
Should get at "Week" level as
Week Day Measure
1 2 5
2 7 9
3 5 10
Thanks! :)
If you want to create a calculated member that can be reused for several measures, you can create a utility dimension that will contain a bunch of calculated member only. Dunno how to do that in SSAS (I'm familiar with icCube). Then you can use this hierarchy in your requests to apply the calculated member.
Let's take your example. I've called the utility dimension [Stats]. Its default member is a calculated member returning the value of the current measure. And it contains the [Last Day] calc. member.
WITH MEMBER [Stats].[Stats].[Last Day] AS (
NonEmpty(
Order( [Trend].[Trend].currentMember.children,
[Trend].[Trend].currentMember.properties( 'key', TYPED ),
BDESC
),
[Stats].[Stats].defaultMember
).item(0),
[Stats].[Stats].defaultMember )
SELECT
[Measures].members on 0,
[Trend].[Trend].[Week].members on 1
FROM [your-cube]
WHERE [Stats].[Stats].[Last Month]
You can see the trick with [Last Month] in the slicer that is applied to each [MEasures] of the SELECT. Then its formula is using a NonEmpty of the [Days] (reversed with the order() based on the key - you might need to adjust) for the current [MEasures].