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))
);
Related
Would much appreciate any help on this.
I have a measure called "Sales" populated with values, however i am trying to turn the "Sales" value to 0, whenever the "Sales Flag" is set to 0.
Important Note: The Sales Flag is based on Date (lowest level of detail).
The difficulty that i am really experiencing and cant get a grip on, is how i am trying the display the MDX outcome.
As explained above, i would want to make the "Sales" value 0 whenever we have a 0 in the "Sales Flag" (which is based on the Date), but when I run the MDX Script I would wan't on the ROWS to NOT display the Date, but instead just the Week (higher Level to Date), as below shows:
I really have spent hours on this and can't seem to understand how we can create this needed custom Sales measure based on the Sales Flag on the date level, but having the MDX outcome display ROWS on Week level.
Laz
You need to define the member in the MDX before the select. Something like that:
WITH MEMBER [Measures].[Fixed Sales] as IIF([Sales Flag].currentMember=1,[Sales], 0)
SELECT [Measures].[Fixed Sales] on 0, [Sales Flag] on 1 from [Cube]
I am writing the code without SSAS here so it might not be the 100% correct syntax but you can get the general idea ;)
You can add the iif in the SELECT part but I find creating member to be the cleaner solution.
SELECT IIF([Sales Flag].currentMember=1,[Sales], 0) on 0, [Sales Flag] on 1 from [Cube]
If you have a control over the cube in SSAS you can create a calculated member there and you can access it easier.
Glad to hear if Veselin's answer works for you, but if not...
Several approaches are also possible.
Use Measure expression for Sales measure:
Use SCOPE command for Day level (if it's Key level of Date dimension). If it's not a key level you have to aggregate on EVERY level (week, year etc) to emulate AggregateFunction of Sales measure but with updated behavior for one flag:
SCOPE([Date].[Your Date Hierarchy].[Day].members,[Measures].[Sales]);
THIS=IIF([Sales Flag].CurrentMember = 1,[Measures].[Sales],0);
END SCOPE;
Update logic in DSV to multiply Sales column by SalesFlag. This is the easiest way from T-SQL perspective.
I'm trying to add a calculated member to my cube, which will return the first fiscal year where there is any data at all in a particular measure.
The purpose is to suppress (i.e. NULLify) various year-on-year calculated measures when the year is this first year: in that year, comparison with the previous year is meaningless.
I've got this so far:
WITH MEMBER Measures.DataStartYear_Sales
AS
HEAD(
NONEMPTY([Calendar].[Fiscal Periods].[Fiscal Year].Members,[Measures].[QuantityOrdered])
,1).Item(0).Properties("NAME")
At the moment:
a. It's a query-scoped measure, as that's easier to experiment with.
b. It returns the first year's Name, as that's easier to see. Eventually I'll just return the member itself, and do an IS comparison against the year hierarchy .CurrentMember in the other calculated member calculations.
The problem I expected, which has happened, is that I only want this measure to be calculated once, over the whole cube. But when I used it in a query, it obviously reacts to the context. For example, if I stick the Products dimension on ROWS, the value of this measure will be different for each row, because each product's earliest order date is different.
That is of course useful, but it's not what I want. Is there some way to force this measure to ignore the query context, and always return the same value?
I looked into SCOPE_ISOLATION and SOLVE_ORDER, but they don't do what I'm trying to do here.
I suppose I could specify a tuple of Dimension1.All, Dimension2.All.... DimensionN.All, covering all dimensions in the cube, but that seems messy and fragile.
I think you might be able to accomplish this with static sets. Here is an example using Adventure Works that produces the same first year regardless of context:
WITH STATIC SET FirstYear AS
HEAD
(
NONEMPTY([Date].[Calendar Year].[Calendar Year].MEMBERS, [Measures].[Internet Sales Amount])
, 1
)
MEMBER FirstYearName AS
FirstYear.ITEM(0).NAME
SELECT
[Measures].[FirstYearName] ON COLUMNS
, [Date].[Calendar Year].[Calendar Year].MEMBERS
//Add as many dimensions as you like here...for example
* [Product].[Product].[Product].MEMBERS
ON ROWS
FROM
[Adventure Works]
;
Example output:
That should hopefully put you on the right track.
I've build a MDX calc member that give me the year-to-date (YTD) for budget, however if the user selects multiple months, it returns the total for year. Which I believe is CurrentMember function, but how do it I get the max from the set?
Aggregate(
PeriodsToDate(
[Date].[Fiscal].[Fiscal Year]
,[Date].[Fiscal].CurrentMember
)
,[Measures].[Budget]
)
So when we have a month slicer to select the month, if the end-user selects more then 1 month, then the CurrentMember fails and the parent is used, so the Full Year (FY) is used.
It might be very late to answer this question but hopefully someone else can benefit with the answer.
for this particualr problem you have to create a dynamic set and apply scope to that. check the below MDX.
dynamic set : existing PeriodsToDate(Date].[Fiscal].[Fiscal Year],[Date].
[Fiscal].CurrentMember)
calcualted member : Aggregate( PeriodsToDate( [Date].[Fiscal].[Fiscal Year]
,[Date].[Fiscal].CurrentMember
)
,[Measures].[Budget]
)
apply scope to it scope (Date].[Fiscal].[Fiscal Year],,[Measures].[Budget])
this = aggregate (([dynamic set],],[Measures].[Budget])
end scope
this way u can select a date range without any problem
Kind Regards
mah
I'm relatively new to MDX (in the process of ordering a book just now) and having a crack at creating a calculated measure, which should sum a value from one of my Fact tables, based on a set range of dates (from my Time dimension) which should be filtered by an attribute from another dimension. Unfortunately, I seem to have gotten myself in a bit of a situation and can't see a clear way out. I looked through other similar questions but didn't see any trying to do this same thing, only single dimension measures.
I have a Measure Group, which contains the physical measure SourceMeasure.
I have a Time dimension, named [Time], which I want to use to specify my range for the calculation. This is related to the above measure group by my Date Key.
I have an Account dimension, named [Dim Account], which contains two date attributes: [Account Start Date] and [Account End Date]. This is related to the above measure group via an Account ID.
What I'm trying to do, is filter the [Time] dimension to a range based on the [Account Start Date] and [Account End Date], and return the sum of [SourceMeasure] for the period specified for that account.
Obviously, this will be different for each account, so shouldn't be aggregated, except by the [Dim Account] dimension (perhaps returning 0 or null if not applied).
Example test expression below, this is currently not working due to an error with the FORMAT_STRING syntax (according to MDX Studio).
WITH
MEMBER [Measures].[LifetimeMeasure] AS
Sum
(
{
StrToMember
(
"[Time].[Date].&["
+ Format([Dim Account].[Account Start Date].CurrentMember.MemberValue,"yyyy-MM-ddThh:mm:ss")
+ "]"
)
:
StrToMember
(
"[Time].[Date].&["
+ Format([Dim Account].[Account End Date].CurrentMember.MemberValue,"yyyy-MM-ddThh:mm:ss")
+ "]"
)
}
,[Measures].[SourceMeasure]
)
SELECT
{
[Measures].[LifetimeMeasure]
,[Measures].[SourceMeasure]
}
ON COLUMNS
,{
[Dim Account].[Account].[AccountName]
}
ON ROWS
FROM
[MyCube]
I've tried a few different approaches (SCOPE, Filter, IIF) but every time I seem to get back to the same sticking point - how to filter the [Time] dimension based on the value of the [Dim Account] start and end dates.
Now, it may be that I'm completely misunderstanding how the relationships work between the dimensions and/or how calculated measures are computed by SSAS but I'm not yet at a level where I'm sure what to look for, so I'm going round in circles.
Is what I'm trying to do possible, and if so, any pointers as to where to look to help me figure out where I'm going wrong? Should I perhaps be looking to use a Calculation Dimension instead?
I hope this all makes sense, let me know if I've missed anything or if more detail is required. I'm testing using MDX Studio.
I found the error by adding the CONSTRAINED flag to the StrToMember function.
It seems that my [Time] dimension's date entries have defaulted to the time "00:00:00" while my [Dim Account] dimension's date entries have defaulted to "12:00:00". It looks like a mismatch between 24-hour and 12-hour clock. My date fields on the [Dim Account] dimension are marked as "Regular", not "Date" due to the fact that the dimension isn't a natural time dimension. I think it's potentially this that's causing the mismatch.
To workaround the issue for now, I've removed the Time format from my Format expression and just appended the "00:00:00" to the string while I search for the root cause. I'll update once I've solved it.
UPDATE: The cause of the mismatch is not in the dimension, but in the format string I've used in the StrToMember expression. It's not documented on MSDN, but the following string outputs 12-hour time format:
"yyyy-mm-ddThh:mm:ss"
While this string outputs 24-hour time format:
"yyyy-mm-ddTHH:mm:ss"
I'm having a bit of trouble accomplishing something that I think should be relatively straightforward in MDX. I would like to create a calculated member that provides a sum of one of my measures over the previous two weeks at a given point in time. My time dimension looks like:
TimeId TradingDate Day of Week
-----------------------------------
1000 11/1/2012 Thursday
1001 11/2/2012 Friday
1002 11/5/2012 Monday
1003 11/6/2012 Tuesday
... ...
What makes this particularly difficult is that my Time dimension is not quite complete. The members of my Time dimension only correspond to trading days in the stock market, and not all time. This means that weekends, holidays, or any other day in which the stock market is closed are excluded. This also means the normal methods of traversing time such as LAG or PARALLELPERIOD will not work quite right here. LAG(14), for example, means "14 trading days", which at any given point could represent a variable length of actual time.
Inside my calculated member, I'm attempting to use FILTER in order to get only time members that are within the previous two weeks of the CurrentMember. However, I can't seem to figure out the proper syntax (if there is one) to accomplish this. I imagine it would be something like:
WITH MEMBER [Sum of Price Previous 2 Weeks] AS
SUM(
FILTER(
[Time].[TimeId].Children
, [Time].[TradingDate].MemberValue
>= VBA!DATEADD("ww", -2, [Time].[TradingDate].CurrentMember.MemberValue)
)
, [Price]
)
However, this doesn't quite work. I can't seem to separate the context of the calculated members current iteration from what would be a separate context inside of the FILTER function. In other words, I'm not sure how to say:
"When iterating over the set inside of FILTER, compare the current
member of each iteration against the value of the CurrentMember in
the scope of the calculated member"
Is what I'm trying to accomplish even possible? Is there a different approach I could be taking to accomplish what I'm after?
The result you'll get from a calculated member will depend on the axis of your query. So first, make sure you have [Time].[TradingDate] in your axis.
Second, your [Time].[TradingDate] hierarchy should be ordered by Key (I assume TradingDate is the key).
Now you can use this member definition:
WITH MEMBER [Sum of Price Previous 2 Weeks] AS
SUM(
[Time].[TradingDate].CurrentMember.Lag(14):[Time].[TradingDate].CurrentMember, [Price]
)
You can use set aliases to refer to the outer CurrentMember in the Filter context:
WITH MEMBER [Sum of Price Previous 2 Weeks] AS
SUM(
GENERATE([Time].[TradingDate].CurrentMember AS CurrentDateAlias,
FILTER(
[Time].[TimeId].Children
, [Time].[TradingDate].MemberValue
>= VBA!DATEADD("ww", -2, CurrentDateAlias.Item(0).MemberValue)
)
)
, [Price]
)
GENERATE is used just to define the alias somewhere.