I have a situation where I need to get active account count on a specific date.
I have start date end date in SQL it looks like
select count(account) where start_date <=#date and end_date >=#date
In MDX, I tried below one
AGGREGATE(
{
NULL:LINKMEMBER
(
[DATE].[YQMWD].CURRENTMEMBER
, [StartDate].[YQMWD]
)
}
*
{
LINKMEMBER
(
[DATE].[YQMWD].CURRENTMEMBER
, [EndDate].[YQMWD]
):NULL
}
, ([Measures].[AccountCount])
)
This Code is returning me perfect on date level only but once I am traversing to Week or Month it is considering the whole month of the active value. But during the selected month period many account getting deactivate.
If anybody faced this kind of measure before like
"Active value on specific date" .
I thought about the following but then noticed that you are dealing with two distinct dimensions [StartDate] and [EndDate] so using the range operator : is incorrect:
AGGREGATE(
UNION(
{
NULL
:
LINKMEMBER(
[DATE].[YQMWD].CURRENTMEMBER
, [StartDate].[YQMWD]
)
}
,{
LINKMEMBER(
[DATE].[YQMWD].CURRENTMEMBER
, [EndDate].[YQMWD]
)
:
NULL
}
)
, ([Measures].[AccountCount])
)
If we look in the definition of LINKMEMBER then it says the following:
https://msdn.microsoft.com/en-us/library/ms146058.aspx
The LinkMember function returns the member from the specified
hierarchy that matches the key values at each level of the specified
member in a related hierarchy. Attributes at each level must have the
same key cardinality and data type. In unnatural hierarchies, if there
is more than one match for an attribute's key value, the result will
be an error or indeterminate.
So it makes sense the behaviour you are encountering - if [DATE].[YQMWD].CURRENTMEMBER is a week, then the key of this member is not going to map across to either [StartDate].[YQMWD] or [EndDate].[YQMWD].
Moreover if a week is selected then how do you interpret this sql logic where start_date <=#date and end_date >=#date as a week is made up of 7 days so #date has 7 possibilities?
Maybe you could use EXISTS function inside the LINKMEMBER function so that only Date level members are used. Then we have this problem that Exists will return a set type but the first arg of LINKMEMBER needs to be of type member. So get hold of the first and last members using Tail and Head like so:
AGGREGATE(
{
NULL
:
LINKMEMBER(
HEAD(
EXISTS(
[DATE].[YQMWD].CURRENTMEMBER
,[DATE].[YQMWD].[Date] ////<<if CURRENTMEMBER is a week then Exists will return a set of 7 Date members
)
,1 ////<<if CURRENTMEMBER is a week then Head(..1) will return a set of 1 Date member - the first date in the week
).ITEM(0).ITEM(0) ////<<this converts from single member set to a member
, [StartDate].[YQMWD]
)
}
*
{
LINKMEMBER(
TAIL(
EXISTS(
[DATE].[YQMWD].CURRENTMEMBER
,[DATE].[YQMWD].[Date]
)
,1
).ITEM(0).ITEM(0)
, [EndDate].[YQMWD]
)
:NULL
}
, ([Measures].[AccountCount])
)
How about first checking for the type of input and then giving results? In this case CoalesceEmpty will check that and return the results. Used FirstChild function to fetch the first date always from the range.
CoalesceEmpty
(
AGGREGATE
(
{NULL:LINKMEMBER([DATE].[YQMWD].CURRENTMEMBER.FIRSTCHILD.FIRSTCHILD.FIRSTCHILD.FIRSTCHILD, [StartDate].[YQMWD])}
*
{LINKMEMBER([DATE].[YQMWD].CURRENTMEMBER.FIRSTCHILD.FIRSTCHILD.FIRSTCHILD.FIRSTCHILD, [EndDate].[YQMWD]):NULL}
, ([Measures].[AccountCount])
)//--If it is a year
,
AGGREGATE
(
{NULL:LINKMEMBER([DATE].[YQMWD].CURRENTMEMBER.FIRSTCHILD.FIRSTCHILD.FIRSTCHILD, [StartDate].[YQMWD])}
*
{LINKMEMBER([DATE].[YQMWD].CURRENTMEMBER.FIRSTCHILD.FIRSTCHILD.FIRSTCHILD, [EndDate].[YQMWD]):NULL}
, ([Measures].[AccountCount])
)//--If it is a quarter
,
AGGREGATE
(
{NULL:LINKMEMBER([DATE].[YQMWD].CURRENTMEMBER.FIRSTCHILD.FIRSTCHILD, [StartDate].[YQMWD])}
*
{LINKMEMBER([DATE].[YQMWD].CURRENTMEMBER.FIRSTCHILD.FIRSTCHILD, [EndDate].[YQMWD]):NULL}
, ([Measures].[AccountCount])
)//--If it is a month
,
AGGREGATE
(
{NULL:LINKMEMBER([DATE].[YQMWD].CURRENTMEMBER.FIRSTCHILD, [StartDate].[YQMWD])}
*
{LINKMEMBER([DATE].[YQMWD].CURRENTMEMBER.FIRSTCHILD, [EndDate].[YQMWD]):NULL}
, ([Measures].[AccountCount])
)//--If it is a week
,
AGGREGATE
(
{NULL:LINKMEMBER([DATE].[YQMWD].CURRENTMEMBER, [StartDate].[YQMWD])}
*
{LINKMEMBER([DATE].[YQMWD].CURRENTMEMBER, [EndDate].[YQMWD]):NULL}
, ([Measures].[AccountCount])
)//--If it is a date
)
Related
I am new to MDX and I am trying to apply date filter to year of date Hierarchy , i.e. I want count of all sales for each product number excluding NA, for date greater than 1/1/2016.
Write now I am using below query :
SELECT NON EMPTY { [Measures].[SALES COUNT] } ON COLUMNS
, NON EMPTY { ([PRODUCT CRIETERIA].[PRODUCT NUMBER].[PRODUCT NUMBER].ALLMEMBERS ) }
DIMENSION PROPERTIES MEMBER_CAPTION, MEMBER_UNIQUE_NAME ON ROWS
FROM
(
SELECT
( -{ [PRODUCT CRIETERIA].[PRODUCT NUMBER].&[NA] } ) ON COLUMNS
FROM
(
SELECT
(
{
[PRODUCT Creation Date].[PRODUCT Creation Date Hierarchy].[PRODUCT Creation Year].&[2016],
[PRODUCT Creation Date].[PRODUCT Creation Date Hierarchy].[PRODUCT Creation Year].&[2017]
}
)
ON COLUMNS FROM [Product_QA]))
WHERE ( [PRODUCT Creation Date].[PRODUCT Creation Date Hierarchy].CurrentMember )
CELL PROPERTIES VALUE, BACK_COLOR, FORE_COLOR, FORMATTED_VALUE, FORMAT_STRING, FONT_NAME, FONT_SIZE, FONT_FLAGS
But above query is working fine , but not right as I have to manually change this query each and every year.
I want result where date > 1/1/2016
How can I use greater than here to get desired result.
Thanks.
I found the solution - in general when using the Date dimension a colon range operator with a NULL on either side gives a range that is open on one side e.g. 2016 and above
[PRODUCT Creation Date].[PRODUCT Creation Date Hierarchy].[PRODUCT Creation Year].&[2016]
: NULL
upto and including 2016:
NULL:
[PRODUCT Creation Date].[PRODUCT Creation Date Hierarchy].[PRODUCT Creation Year].&[2016]
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 to create a calculated measure showing the SUM of a measure over a period of time FROM a current member of a date dimension TO now.
The following code is pretty bad but I hope it will give you an idea:
With Member [Measures].[NumberFromDate] as (
sum(
[Date].currentMember:STRTOMEMBER(Format(Now() , '[Date]\.&[yyyy-mm-dd hh:mm:ss.0]' )
), [Measures].[Number]
)
In my schema Date is a Dimension with a single Level Date of type Date.
This mdx code give me an error "Cannot find MDX member '[Date]'".
Try strToSet instead:
With Member [Measures].[NumberFromDate] as (
sum(
strToSet(
'[Date].currentMember:[Date].[' & Format(Now() ,'yyyy-mm-dd hh:mm:ss.0') & ']'
)
)
, [Measures].[Number]
)
Here is a very similar request on MSDN:
https://social.msdn.microsoft.com/Forums/sqlserver/en-US/fdee9f45-8383-4446-b022-e9e877477aec/mdx-date-format
I'm a bit unsure if your format sring is ok. Is this really the string used in your cube?
'yyyy-mm-dd hh:mm:ss.0'
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];
I'm a newcomer to SQL MDX and don't know exactly how to achieve this.
I need to get data from my cube for the last X days from the last available data.
The following is my code:
SELECT { [Measures].[Fact Stays Count], [Measures].[Time Spent] } ON COLUMNS,
NON EMPTY { ( [Dim Locals].[Local Description].[Local Description].ALLMEMBERS * [FK Date].[Date].[Date] ) } ON ROWS
FROM
(
select { TAIL(FILTER([FK Date].[Date].MEMBERS, NOT ISEMPTY([FK Date].[Date].CURRENTMEMBER)),30) } ON COLUMNS
FROM (
SELECT ( STRTOSET(#userId, CONSTRAINED) ) ON COLUMNS
FROM [DW]
)
)
The problem is the query returns the last 30 days where data exists, not the last 30 consecutive calendar days.
How can I change the query to get the results I want?
Try this. The only thing I changed is the select with the dates in it. Instead of asking for the last 30 days where there is data for the measures, I'm asking for the last day where there is data for the measures, getting that last item and then doing the lag of 29 days for the beginning of the date range and then without the lag (to the last day with data) for the end of the date range.
SELECT { [Measures].[Fact Stays Count], [Measures].[Time Spent] } ON COLUMNS,
NON EMPTY { ( [Dim Locals].[Local Description].[Local Description].ALLMEMBERS * [FK Date].[Date].[Date] ) } ON ROWS
FROM
(
select { TAIL(FILTER([FK Date].[Date].MEMBERS, NOT ISEMPTY([FK Date].[Date].CURRENTMEMBER)),1).item(0).lag(29): TAIL(FILTER([FK Date].[Date].MEMBERS, NOT ISEMPTY([FK Date].[Date].CURRENTMEMBER)),1).itm(0)} ON COLUMNS
FROM (
SELECT ( STRTOSET(#userId, CONSTRAINED) ) ON COLUMNS
FROM [DW]
)
)
Be aware that the way you have the query now will return the last day where there is data for both measures. If those two measures don't line up it might not provide what you want. For instance, if there is data through Dec 30 2013 on Fact Stays Count and data through Jan 5 2014 on Time Spent, it would return Dec 30 2013. If you want it to depend on both measures, you are good. If you want it to depend on one measures, you can switch it to be something like the below instead.
Tail(Filter([FK Date].[Date].[Date].MEMBERS.MEMBERS, [Measures].[Fact Stays Count] >0),1).item(0)