SSAS MDX Problem with IIF and TAIL() function - mdx

Experts,
I am using SQL SSAS Std. 2017 and in the end want to create a calculated member that returns either the last month's day of my data or the current day if the last existing data is of today.
(=> If today is Aug-31 I want to retrieve Aug-31 of my data, otherwise if today is e.g. Aug-30 retrieve Jul-31)
To develop this member I am currently in the process of creating a MDX query in SQL Server. I am having difficulties to understand what is actually a "tuple set expression" (because the TAIL() function shall return a subset (ergo set) according to MSDN) but in fact I am receiving errors when playing around with the .Item(0) function on its result. In MSDN I cannot find information about "tuple sets" and how to make them do, what I want.
My Date Dimension has a Hierarchy JMT (Year | Month | Day | Date Key of type DATE).
To receive the most current date member of the cross product I am using the TAIL(NONEMPTY(Date...Members, { (DimX.&.. , DimY.&.. , DimZ.&..) })) expression which works fine.
But how do I choose between today's or the previous month's date?
My MDX for testing purposes on February (2) is as follows:
SELECT {
IIF(
TAIL(NONEMPTY([DateDim].[JMT].[T].Members, { ([DimX].[X].&[200], [DimY].[Company].&[4499166], [DateDim].[JMT].[M].&[2020]&[2]) })).Item(0) --.Properties('Date Key', TYPED)
> NOW()
, TAIL(NONEMPTY([DateDim].[JMT].[T].Members, { ([DimX].[X].&[200], [DimY].[Company].&[4499166], [DateDim].[JMT].[M].&[2020]&[1]) }))
, TAIL(NONEMPTY([DateDim].[JMT].[T].Members, { ([DimX].[X].&[200], [DimY].[Company].&[4499166], [DateDim].[JMT].[M].&[2020]&[2]) }))
)
-- ,
-- TAIL(NONEMPTY([DateDim].[JMT].[T].Members, { ([DimX].[X].&[200], [DimY].[Company].&[4499166], [DateDim].[JMT].[M].&[2020]&[2]) })) } on columns
, { [Measures].[Turnover] } on rows
FROM [Finance]
Result:
As you can see, the IIF function does not do what I want. It assumes .Item(0) is greater than NOW() therefore returning the "31" member of January (1). Expected: "29" of February.
I guess, it might be a problem with the data types and the actual value returned by .Item(0). But if I want to use the .Properties('Date Key', TYPED) it states "The Date Key Dimension Attribute could not be found. See below picture.
In the image of the DateDim it should be "DateDim.JMT" in the blue area ;-).
Do you have any suggestions?
Thank you, Cordt

If you switch this:
TAIL(NONEMPTY([DateDim].[JMT].[T].Members, { ([DimX].[X].&[200], [DimY].[Company].&[4499166], [DateDim].[JMT].[M].&[2020]&[2]) })).Item(0)
to the following does it help?
Tail
(
NonEmpty
(
[DateDim].[JMT].[T].MEMBERS
,{
(
[DimX].[X].&[200]
,[DimY].[Company].&[4499166]
,[DateDim].[JMT].[M].&[2020]&[2]
)
}
)
).Item(0).Item(0).MemberValue

Related

Kettle Datedif month issue

I need to reproduce the kettle Datedif function in the R programming language. I need the 'datedif month' option. I thought reproducing would be pretty easy but I have some 'weird behaviour' in pentaho. As an example:
ID date_1 date_2 monthly_difference_kettle daydiff_mysql
15943 31/12/2013 28/07/2014 7 209
15943 31/12/2011 27/07/2012 6 209
So in pentaho kettle I used the formula-step and the function DATEDIF(date2,date1,"m"). As you can see when I calculate the daily difference in mysql I get for both records the same amount of days in difference (209), however, when the monthly difference is calculated via the formula step in pentaho kettle I get a different result in months (7 and 6 respectively). I don't understand how this is calculated...
Can anyone produce the source code for the 'DATEDIF months' function in pentaho? I would like to reproduce it in R so I get exactly the same results.
Thanks in advance,
best regards,
Not sure about mysql, but i think it is the same. In PostgreSQL date difference gives integer value (in days). It means both rows has total match in days.
Calculating month difference non trivial. What is month (28, 30, 31 day)? Shall we count if month is not full?
Documentation states If there is not a complete month between the dates, 0 will be returned
But according to source code easy to understand how calculated datedif:
Source code available via github https://github.com/pentaho/pentaho-reporting/blob/f7defbcfc0e8f48ad2b139fe9820445f052e0e78/libraries/libformula/src/main/java/org/pentaho/reporting/libraries/formula/function/datetime/DateDifFunction.java
private int addFieldLoop( final GregorianCalendar c, final GregorianCalendar target, final int field ) {
c.set( Calendar.MILLISECOND, 0 );
c.set( Calendar.SECOND, 0 );
c.set( Calendar.MINUTE, 0 );
c.set( Calendar.HOUR_OF_DAY, 0 );
target.set( Calendar.MILLISECOND, 0 );
target.set( Calendar.SECOND, 0 );
target.set( Calendar.MINUTE, 0 );
target.set( Calendar.HOUR_OF_DAY, 0 );
if ( c.getTimeInMillis() == target.getTimeInMillis() ) {
return 0;
}
int count = 0;
while ( true ) {
c.add( field, 1 );
if ( c.getTimeInMillis() > target.getTimeInMillis() ) {
return count;
}
count += 1;
}
}
Append 1 month to start date till it will become bigger then end date

MDX-Query - Query with to many rows. Set correct filter

I work on a problem with an MDX Query.
The cube contains models and serials (units) and should show all units in warranty for each year.
This is the a cube with this Dimensions/Measures:
CubeOverview
Now I would select all Serials which are in warranty for a special year.
The problem is that the whole Table v Dim Unit Model 4IB Test contains more than 50 Mio rows which results alsways to an QueryTimeout or sometimes to an MemoryException.
At the moment I have a MDX query (see below) which works if I select special model. But I need the filter to all models.
WITH
MEMBER [Measures].[QtyTotal] AS
[Measures].[QtyInWarranty] + [Measures].[QtyInExtension]
SELECT
NON EMPTY
{
[Measures].[QtyStdOut] ,[Measures].[QtyInExtension] ,[Measures].[QtyStdIn]
,[Measures].[QtyInWarranty] ,[Measures].[QtyTotal] ,[Measures].[SumStartWarranty]
} ON COLUMNS
,NON EMPTY
{
crossjoin(
[v Dim Unit Model 4IB Test].[ModelUnitMapping].[Id Unit].Members
,[Dim Country].[Id Country].[Id Country].members
,[Dim Calendar].[Calendar].[Month Name4report].members
)
} ON ROWS
FROM
(
SELECT
{
[v Dim Unit Model 4IB Test].[model no short].[Model No Short].&[SampleModel]
} ON COLUMNS
FROM
(
SELECT
{
[Dim Calendar].[Calendar].[Year].&[2015]
} ON COLUMNS
FROM [InstalledBaseCS_Serial]
)
)
Does anybody knows a tip to update the query to get all units for one year (round about 4 Mio rows)?
If you're trying to return the results to a visible grid in MDXstudio or SSMS then it may be timing out because there is quite a bit to render.
If you use OPENQUERY or the CLR OLAP Extensions then try the following:
Do not return the results to the screen but INSERT results into a table.
Simplifiy your script by taking away the custom measure. This can easily be calculated later as it is trivial: I have a feeling it is slowing down ssas.
Script
SELECT
NON EMPTY
{
[Measures].[QtyStdOut]
,[Measures].[QtyInExtension]
,[Measures].[QtyStdIn]
,[Measures].[QtyInWarranty]
,[Measures].[SumStartWarranty]
} ON 0
,NON EMPTY
[v Dim Unit Model 4IB Test].[ModelUnitMapping].[Id Unit].Members
*[Dim Country].[Id Country].[Id Country].members
*[Dim Calendar].[Calendar].[Month Name4report].members
ON 1
FROM
(
SELECT
[v Dim Unit Model 4IB Test].[model no short].[Model No Short].&[SampleModel] ON 0
FROM
(
SELECT [Dim Calendar].[Calendar].[Year].&[2015] ON 0
FROM [InstalledBaseCS_Serial]
)
);

MDX,how to flatten the result of Descendants function

I have a hierarchy with 5 level,I use Descendants() to retrieve all lower level of a member.But i end up with a one column result where i like to have a result with one column for each level.So on each row i repeat the parent,grand parents etc of the current member.
WITH
MEMBER [Measures].[key] AS
[DimGLAcct].[MgtCOA].CurrentMember.UNIQUENAME
MEMBER [Measures].[level_] AS
[DimGLAcct].[MgtCOA].CurrentMember.level.ordinal
SELECT
{
[Measures].[key]
, [Measures].[level_]
, [Measures].[Actuals]
} ON COLUMNS,
{
Descendants(
[DimGLAcct].[MgtCOA].[Mparent5].&[MCOA].&[400000M - Total operating overhead expenses].&[440000M - Other expenses].&[441000M - Other expenses]
,
,SELF_AND_AFTER
)
} ON ROWS
FROM [Model];
I cannot quite suss out the names of your levels but it is ok to do the following in mdx:
WITH
MEMBER [Measures].[key] AS
[DimGLAcct].[MgtCOA].CurrentMember.UNIQUENAME
MEMBER [Measures].[level_] AS
[DimGLAcct].[MgtCOA].CurrentMember.level.ordinal
SELECT
{
[Measures].[key]
, [Measures].[level_]
, [Measures].[Actuals]
} ON COLUMNS,
[DimGLAcct].[LevelX]
*[DimGLAcct].[LevelY]
*[DimGLAcct].[LevelZ]
*[DimGLAcct].[LevelK]
ON ROWS
FROM [Model];
Each of the levels in your user hierarchy will have respective attribute hieraries - which are used in the above.

MDX Filtering dimension members with result of other dimension

I would like to filter a dimension for cube security with some information that are in another dimension.
So - I have a dimension which holds some account Responsible (Account Number and the initials on the one responsible) and another Dimension with all accounts.
I would like to make sure, that a person only can see movements on the accounts on which they are responsible.
I can make the filtering work like this:
SELECT
{} ON 0
,{
Exists
(
Filter
(
[Accounts].[Accounts].[AccountNo]
*
[AccountResponsible].[AccountResponsible].[AccountNo]
,
[Accounts].[Accounts].Properties("key")
=
[AccountResponsible].[AccountResponsible].Properties("key")
)
,[AccountResponsible].[Responsible].&[MSA]
)
} ON 1
FROM mycube;
the problem is, that there are two columns, and I can't use that in cube security. Is there a way to rewrite this, so that I actually get only one column with the members that the user are allowed to see?
Try using the Extract function:
SELECT
{} ON 0
,
EXTRACT(
{
Exists
(
Filter
(
[Accounts].[Accounts].[AccountNo]
*
[AccountResponsible].[AccountResponsible].[AccountNo]
,
[Accounts].[Accounts].Properties("key")
=
[AccountResponsible].[AccountResponsible].Properties("key")
)
,[AccountResponsible].[Responsible].&[MSA]
)
}
,[Accounts].[Accounts] //<<HIERARCHY YOU WISH TO EXTRACT
) ON 1
FROM mycube;

MDX Dynamic Set Filter Measuers

I am new to MDX.
I want to create a Dynamic Set on SSAS (SQL Server 2014) where this Set filters all Measures
where Measure Date is greater than the current selected date.
Is this possible with a Dynamic Set if not which other solutions are possible?
ID|Date |MeasureVal
1 |15.01.2014| 100
2 |16.01.2014| 150
3 |20.02.2014| 500
4 |21.02.2014| 150
So when the User select this Set and the Date Filter is on 16.01.2014 it should show return Measures with Date greater than 16.01.2014.
From the above example it should return Measures with ID 3,4
Here is my Try
CREATE DYNAMIC SET CURRENTCUBE.[MyTestSet]
AS
Filter (
[Production Time].[Time Hierarchy].[Date].AllMembers ,
( [Production Time].[Time Hierarchy].[Date].CurrentMember.member_caption > "Current selected Date?" )
;
Maybe this?
CREATE DYNAMIC SET CURRENTCUBE.[MyTestSet]
AS Filter(
[Production Time].[Time Hierarchy].[Date].Members as dtSet,
dtSet.Item(
dtSet.CurrentOrdinal-1
).member_caption > "Current selected Date?"
);
But I don't think member_caption will return a number so how will > function?
Usually if you want a set of dates greater than a specified member in mdx you use the range operator, which is a colon : couple with a null on one side of the colon. So here are two example:
WITH
SET [GreaterThanX] AS
{
[Production Time].[Time Hierarchy].[Date].[01 Jan 2014]
:
null
}
SET [LessThanX] AS
{
null
:
[Production Time].[Time Hierarchy].[Date].[01 Jan 2014]
}
SELECT
{} ON 0,
[GreaterThanX] ON 1
//[LessThanX] ON 1
FROM myCube;
Try the above - the first should give you all dates after 01 Jan whereas the second all dates less than.
note: when using the : operator it is important that the specified member, in this case [Production Time].[Time Hierarchy].[Date].[01 Jan 2014] exists in the cube - if it doesn't exist no error occur but the expression is evaluated as null:null i.e. all dates will be returned.