1.This works:
MEMBER [Measures].[DaysComplete] AS
Descendants
(
Tail([Date].[Date - Calendar Month].[Calendar Month]).Item(0)
,[Date].[Date - Calendar Month].[Calendar Day]
,SELF
).Count
Returns 16 as expected as 1-16 October are in our cube
2.This doesn't work:
MEMBER [Date].[Date - Calendar Month].[Month] AS
Tail([Date].[Date - Calendar Month].[Calendar Month]).Item(0)
MEMBER [Measures].[DaysComplete] AS
Descendants
(
[Date].[Date - Calendar Month].[Month]
,[Date].[Date - Calendar Month].[Calendar Day]
,SELF
).Count
Returns the integer 0
Why does the 2. return 0?
In your second approach, you create a new member of the [Date].[Date - Calendar Month] hierarchy, you do not create a reference to the existing member. This new member - like all calculated members - does not have any descendants.
If you need the original member, not a new one, in your calculation, then you could get around that with a named set containing just this member. The set - even if it itself is a new object - would contain the original member, not a new one.
I would assume that
SET [My Month] AS
Tail([Date].[Date - Calendar Month].[Calendar Month])
MEMBER [Measures].[DaysComplete] AS
Descendants
(
[My Month].Item(0)
,[Date].[Date - Calendar Month].[Calendar Day]
,SELF
).Count
would deliver what you expect.
Related
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'm trying to create a measure in MDX to get the first day in the selected period (I have a YMD date dimension). I'm using EXISTING function to get the selected members. It's working fine if I only select one dimension member in Excel pivot table filter. However, as soon as I select multiple members (Example: 2012 & 2013 together), the EXISTING function is not working as expected.
I've created another measure to debug and see what is going on. The measure is defined as:
SetToStr(EXISTING([Date].[Date YMD].[Year].members))
If I have only one dimension member selected, this works fine, I get this back:
{[Date].[Date YMD].[All].[2013]}
However, as soon as I select 2012 and 2013 together, I get a list of all dimension members back:
{[Date].[Date YMD].[All].[N/A],[Date].[Date YMD].[All].[2007],[Date].[Date YMD].[All].[2008],[Date].[Date YMD].[All].[2009],[Date].[Date YMD].[All].[2010],[Date].[Date YMD].[All].[2011],[Date].[Date YMD].[All].[2012],[Date].[Date YMD].[All].[2013],[Date].[Date YMD].[All].[2014]}
The EXISTING function seems to work only when a single member is selected?
--
Update:
Maybe I was not clear enough in the original post. The problem I'm facing is getting the first and last date member if the date dimension is being filtered (in an Excel pivot table filter) and multiple date members are selected in the filter (example: when years 2012 & 2013 are selected together).
I've tried using the solution from here: http://bimic.blogspot.com/2011/07/mdx-rewrite-query-with-currentmember.html, but to no success.
I've created 2 measures now:
First Day Single:
HEAD(
DESCENDANTS(
[Date].[Date YMD].CURRENTMEMBER,
[Date].[Date YMD].[Day]
),
1
).ITEM(0).member_value
First Day Multiple Years
MIN(EXISTING [Date].[Date YMD].[Year].members, [Measures].[First Day Single])
Unfortunately I can't include a screenshot directly. You can see it on this link: http://social.msdn.microsoft.com/Forums/getfile/446659
As you can see, the measures work when a single year is selected in the pivot table filter, but don't work when you select more than one year.
In my cube and via management studio I can write a script like this to create measures that return numeric values based on the first day and last day of each month:
WITH
SET [Last12Months] AS
TAIL (
[Date].[Date - Calendar Month].[Calendar Month].members,
12)
MEMBER [Measures].[FirstDay] AS
HEAD(
DESCENDANTS(
[Date].[Date - Calendar Month].CURRENTMEMBER,
[Date].[Date - Calendar Month].[Calendar Day]
),
1
).ITEM(0).member_value
MEMBER [Measures].[LastDay] AS
TAIL(
DESCENDANTS(
[Date].[Date - Calendar Month].CURRENTMEMBER,
[Date].[Date - Calendar Month].[Calendar Day]
),
1
).ITEM(0).member_value
SELECT
{[Measures].[FirstDay],[Measures].[LastDay]} ON 0,
[Last12Months] ON 1
FROM [MyCube]
We use Office 2010 but using the OLAP Pivottables extensions add-in I can add the following two measures to my pivottable:
1.[Measures].[FirstDay]
HEAD(
DESCENDANTS(
[Date].[Date - Calendar Month].CURRENTMEMBER,
[Date].[Date - Calendar Month].[Calendar Day]
),
1
).ITEM(0).member_value
2.[Measures].[LastDay]
TAIL(
DESCENDANTS(
[Date].[Date - Calendar Month].CURRENTMEMBER,
[Date].[Date - Calendar Month].[Calendar Day]
),
1
).ITEM(0).member_value
Now whatever I use in Rows I get the correct answer from the pivot:
EDIT
If I manipulate the pivot so that our date dimension is in the pivot's filter and then go for multi-select of 2013 and 2014 it seems that the `mdx' which excel is using is the following:
WITH
MEMBER [Measures].[FirstDay] as
HEAD (
DESCENDANTS ( [Date].[Date - Calendar Month].CURRENTMEMBER, [Date].[Date - Calendar Month].[Calendar Day] )
, 1
).ITEM( 0 ).member_value
MEMBER [Measures].[LastDay] as
TAIL (
DESCENDANTS ( [Date].[Date - Calendar Month].CURRENTMEMBER, [Date].[Date - Calendar Month].[Calendar Day] )
, 1
).ITEM( 0 ).member_value
SELECT
{ [Measures].[FirstDay], [Measures].[LastDay] } ON COLUMNS
FROM
(
SELECT
({ [Date].[Date - Calendar Month].[Calendar Year].&[2012],
[Date].[Date - Calendar Month].[Calendar Year].&[2013] }) ON COLUMNS
FROM [OurCube]
)
I think the context of the function CURRENTMEMBER in the custom measures of this script will be lost because of the sub-select.
There is a workaround for your problem described here: http://sqlblog.com/blogs/mosha/archive/2007/09/26/how-to-detect-subselect-inside-mdx-calculations-aka-multiselect-in-excel-2007.aspx. But, as the writer (one of the developers of SSAS) writes, " the solution is neither elegant nor efficient". Anyway, it needs another measure group to be added to the cube, and a stored procedure to be written.
Really old topic, but I am posting my solution here as I haven't found the solution elsewhere:
Using dynamic set seems to have done the trick for me as will be populated only with members in context:
CREATE DYNAMIC SET [LastUpdateSet]
AS
TAIL(
NONEMPTY(
[LastUpdateDate].[Date].ALLMEMBERS
, [Measures].[Quantity]
)
, 1)
;
CREATE MEMBER CURRENTCUBE.[Measures].[LastUpdateQuantity]
AS (
[LastUpdateSet].item(0)
, [Measures].[Quantity]
)
;
This seems pretty logical:
WITH
MEMBER [Date].[Date - Calendar Month].[Calendar Year].&[2013].[LastMth] AS
IIF(
Day(Now()) = 1,
TAIL([Date].[Date - Calendar Month].[Calendar Month],2).Item(1),
TAIL([Date].[Date - Calendar Month].[Calendar Month],2).Item(0)
)
SELECT
NON EMPTY
{
[Date].[Date - Calendar Month].[LastMth],
[Date].[Date - Calendar Month].[LastMth].PARENT
}
ON COLUMNS,
NON EMPTY
[Measures].[BillableIncome]
ON ROWS
FROM [ourCube]
I specify the parent of the calculated member in the first line of the script - so my member LastMth has 2013 as it's parent and sure enough the result set throws back the total for 2013 as well as the last month.
If I make it's parent 2012 in the first line:
WITH
MEMBER [Date].[Date - Calendar Month].[Calendar Year].&[2012].[LastMth] AS
IIF(
...
...
...it doesn't worry about where I get LastMth from (2013) and makes 2012 it's parent as instructed - slightly bizarre but understandable behaviour.
The following returns an empty set for the parent - I thought the parent would be [Date].[Date - Calendar Month].[(All)]? What is the parent and how can I expose it's value?
WITH
MEMBER [Date].[Date - Calendar Month].[LastMth] AS
IIF(
Day(Now()) = 1,
TAIL([Date].[Date - Calendar Month].[Calendar Month],2).Item(1),
TAIL([Date].[Date - Calendar Month].[Calendar Month],2).Item(0)
)
SELECT
NON EMPTY
{
[Date].[Date - Calendar Month].[LastMth],
[Date].[Date - Calendar Month].[LastMth].PARENT
}
ON COLUMNS,
NON EMPTY
[Measures].[BillableIncome]
ON ROWS
FROM [ourCube]
If you do not state a parent for a calculated member, it gets a sibling of the All member, not a child of it.
As an aside: I found that most client tools - including Excel - do not expect All to have siblings, and thus if you create a calculated member in the calculation script (as opposed to just defining it in the WITH clause of a statement), do not display these, even if they are instructed to show calculated members.
This is ok and returns the sum of the default measure for the past 30 days:
SELECT
FROM [OurCube]
WHERE (
closingperiod(
[Date].[Date - Calendar Month].[Calendar Day],
[Date].[Date - Calendar Month].defaultmember
):
closingperiod(
[Date].[Date - Calendar Month].[Calendar Day],
[Date].[Date - Calendar Month].defaultmember
).ITEM(0).LAG(30)
)
How do I transfer the set of dates in the WHERE clause into the WITH clause ?
I attempted the following but it creates the error message detailed:
WITH
SET [30Days] AS
{
closingperiod(
[Date].[Date - Calendar Month].[Calendar Day],
[Date].[Date - Calendar Month].defaultmember
):
closingperiod(
[Date].[Date - Calendar Month].[Calendar Day],
[Date].[Date - Calendar Month].defaultmember
).ITEM(0).LAG(30)
}
SELECT
FROM [OurCube]
WHERE (
[30Days]
)
Executing the query ...
The definition of the 30Days set contains a circular reference.
Execution complete
I believe this is a limitation of SSAS and has something to do with the execution processing of the different parts of the query; even using a SUB-QUERY (i.e., FROM ( SELECT ... )) instead of a WHERE would not solve the issue.
You can define your set at schema level :
CREATE STATIC SET [OurCube].[30Days] as ...
Or depending on your client application at session level:
CREATE SESSION STATIC SET SET [OurCube].[30Days] as ...
The following returns the last member in our set of months:
TAIL([Date].[Date - Calendar Month].[Calendar Month],1)
Our cube contains data upto and including yesterday - so if the above is run today it returns the member [July 2013].
I want the Last Completed Month so if run today (4th July) it should return [June 2013].
Not sure if this adds some extra complexity but if the expression is run on the first of a month then the last member in the hierarchy will actually be equal to the Last Complete Month.
So sometime the last completed month is the last member, and sometime it is the next but last member, in the hierarchy [Calendar Month]
Is there a fool-proof way of coding this expression?
You can determine easily if 'now' is the first day of month as following:
IIF( Day(Now()) = 1, ... , ... )
So you can create a calculated member :
with member [Last Completed Month] as
IIF( Day(Now()) = 1,
TAIL([Date].[Date - Calendar Month].[Calendar Month],1)(0),
TAIL([Date].[Date - Calendar Month].[Calendar Month],2)(0)
)
dunno about the [Calendar Month] hierarchy structure, but perhaps using a lastChild and lastChild.prevMember would be more efficient...
[edit] Tail( ... )(n) retrieve the n-th element of the set returned by Tail - this is a shortcut of item(n)
[edit] imagine the month hierarchy is flat under a all member: [Calendar Month].[All].lastChild would do the same as the Tail() and lastChild.prevMember to get the one before the last.