MDX - filter by [Day] but display category of [Month] - mdx

I’m hoping someone can help me out with restructuring/rewriting my MDX query – I’m fairly new to MDX and only know enough to be dangerous. I am using Mondrian if that makes a difference.
Here is the stacked bar chart I am producing…
Injuries by Month and Category
And here is my query (simplified to remove all the stuff not relevant to this question)…
WITH
SET [Date Range] AS {${mdxStartDateParam}.Parent : ${mdxEndDateParam}.Parent}
MEMBER [Measures].[Month Name] as [Incident Date.YQMD].currentmember.parent.parent.name || "-" || [Incident Date.YQMD].currentmember.name
SET [Classification Month Set] AS (
Hierarchize(
ORDER(
Hierarchize(FILTER([Classification].[Classification].members,[Classification].CURRENTMEMBER IN {Descendants([Classification].[${paramInjClass}])})),
[Measures].[Injury Count],
BDESC
)
) * [Date Range]
)
SELECT {[Measures].[Injury Count], [Measures].[Month Name]} ON COLUMNS,
NON EMPTY [Classification Month Set] ON ROWS
FROM [Injury Analysis]
The problem I have is that my two date parameters (${mdxStartDateParam} and ${mdxEndDateParam}) can be any date at the [Day] level, while my chart X Axis is showing at the [Month] level, and even if the ${mdxStartDateParam} is midway through a month my query is returning all data for the month.
eg. If I have an Injury that occurred on February 2nd but my ${mdxStartDateParam} is [Incident Date.YQMD].[2017].[Q1].[Feb].[17], then that Injuryis being included in the chart.
Is there a way I can restructure my MDX so that the bar for February does not show all data for February, but only the data for Fenruary that is >= ${mdxStartDateParam} and <= ${mdxEndDateParam}?

Since the Mondrian doesn't support sub-queries, you can't use your Calendar hierarchy for both where clause and axis. Also there is no way to filter days and show month only on axis. So, if you have two separate hierarchies for Days and Months, you may use the following:
WITH
SET [Date Range] AS [YourDateDim].[YourHierarchyNotInDateParam].[MonthLevel].Members
MEMBER [Measures].[Month Name] as [Incident Date.YQMD].currentmember.parent.parent.name || "-" || [Incident Date.YQMD].currentmember.name
SET [Classification Month Set] AS (
Hierarchize(
ORDER(
Hierarchize(FILTER([Classification].[Classification].members,[Classification].CURRENTMEMBER IN {Descendants([Classification].[${paramInjClass}])})),
[Measures].[Injury Count],
BDESC
)
) * [Date Range]
)
SELECT {[Measures].[Injury Count], [Measures].[Month Name]} ON COLUMNS,
NON EMPTY [Classification Month Set] ON ROWS
FROM [Injury Analysis]
WHERE {${mdxStartDateParam}:${mdxEndDateParam}})
Otherwise you have to deal with shown days and group them after.

Without knowing anything about the dialect of MDX you're using, or being able to see the dimension structure, my guess is that the problem is with the definition of [Date Range]:
SET [Date Range] AS {${mdxStartDateParam}.Parent : ${mdxEndDateParam}.Parent}
If the two parameters are at the Day level, does .Parent return their parent months?
The solution might be to make the date range be a set of days:
SET [Date Range] AS {${mdxStartDateParam} : ${mdxEndDateParam}}
and then aggregate by month somehow.

Related

MDX Dynamic dimension filter based on value of other dimension

How can I filter using values from two dimension in MDX?
The required result should include records where [Purchase Date].[Date] is before today minus number of years from [Accounting Date].[Year]. So, the result should include YoY records from today based on [Purchase Date].[Date] for each [Accounting Date].[Year] member.
I would like something like the following:
SELECT NON EMPTY [Measures].[Amount] ON 0,
NON EMPTY [Accounting Date].[Year].[Year].ALLMEMBERS ON 1
FROM [Tabular_Model]
WHERE (
NULL :
STRTOMEMBER("[Purchase Date].[Date].&["+ Format(DateAdd("YYYY", [Accounting Date].[Year].CURRENTMEMBER.MEMBER_VALUE - 2020, Now()),"yyyy-MM-ddT00:00:00") + "]")
)
But it fails with error: Execution of the managed stored procedure DateAdd failed with the following error: Microsoft::AnalysisServices::AdomdServer::AdomdException.
The syntax for 'All' is incorrect. (All).
Why CURRENTMEMBER.MEMBER_VALUE works for HAVING but not in my WHERE clause? What is the right way?
Try the following measure and query:
WITH
MEMBER [Measures].[Trailing Amount] as SUM({NULL :
STRTOMEMBER("[Purchase Date].[Date].&["+ Format(DateAdd("YYYY", [Accounting Date].[Year].CURRENTMEMBER.MEMBER_VALUE - 2020, Now()),"yyyy-MM-ddT00:00:00") + "]")}, [Measures].[Amount])
SELECT [Measures].[Trailing Amount] ON 0,
NON EMPTY [Accounting Date].[Year].[Year].MEMBERS ON 1
FROM [Tabular_Model]
If MDX doesn't perform as well as you hope, then you might consider adding the following DAX measure into your Tabular model. The following DAX query illustrates how to use it, but if you put this DAX measure into your model, you can query it with MDX queries and it should likely perform better than an MDX calculation:
define
measure 'Your Table Name Here'[Trailing Sales] =
VAR YearOffset = SELECTEDVALUE('Accounting Date'[Year]) - 2020
VAR NowDate = NOW()
VAR EndDate = DATE(YEAR(NowDate)+YearOffset,MONTH(NowDate),DAY(NowDate))
RETURN CALCULATE([Amount], 'Purchase Date'[Date] <= EndDate)
evaluate ADDCOLUMNS(ALL('Accounting Date'[Year]),"Trailing Sales",[Trailing Sales])

SSAS MDX sum up on memberships in date hierarchies?

In a cube that contains memberships of a club, I have a column MembersInOut in my fact-table which holds when a member joined the club (Value = 1) and leaving (value = -1). The Club started jan 1. 2000. so no members before that date.
Now to know the current number of members on a specific date I can do this:
CREATE MEMBER CURRENTCUBE.[Measures].[Calculated MembersOfTheClub]
AS
Sum(
{[Date Dim].[Date].&[2000-01-01T00:00:00]:
[Date Dim].[Date].currentmember},
[Measures].[MembersInOut]
)
This works fine on the actuel date, but how to make this work on a date hierarchie [Year-Month-day] ?
Thanks
You could create Y-M-D hierarchy, then use expression like below
with member[Measures].[S1] AS
sum(
{NULL:[Date].[Calendar Date].CurrentMember}
, [Measures].[Internet Sales Count])
select nonempty ([Date].[Calendar Date].members) on rows, nonempty ({[Measures].[S1],[Measures].[Internet Sales Count]}) on columns from [Analysis Services Tutorial]
Zoe

MDX Column Alias for use in SQL

I'm trying to query our SSAS cubes and return the values into a SQL view for use as parameters in cube based reports.
I need to return 3 values for financial seasons based on the date hierarchy.
This is the below code, which returns the correct data.
WITH
MEMBER [CurrentHalf] AS [Date - Master].[Financial Calendar].CURRENTMEMBER.UNIQUENAME
MEMBER [NextHalf] AS [Date - Master].[Financial Calendar].LEAD(1).UNIQUENAME
MEMBER [PreviousHalf] AS [Date - Master].[Financial Calendar].LEAD(-1).UNIQUENAME
SELECT {[Date - Master].[Financial Calendar].[Season Half]} ON COLUMNS ,
{[CurrentHalf],NextHalf,PreviousHalf} ON ROWS
FROM [Sales and Stock]
WHERE (Filter([Date - Master].[DateKey].Members,[Date - Master].[DateKey].MemberValue = (format(now(),"dd/MM/yyyy"))))
However the column name for [Date - Master].[Financial Calendar].[Season Half] returns the caption value (e.g. 2014- Autumn /Winter).
See image:
Normally this would be fine however as I am passing it into SQL I need a column name to select off. What I need is to rename this column to something else (e.g. HalfName)
I have tried
WITH
MEMBER [CurrentHalf] AS [Date - Master].[Financial Calendar].CURRENTMEMBER.UNIQUENAME
MEMBER [NextHalf] AS [Date - Master].[Financial Calendar].LEAD(1).UNIQUENAME
MEMBER [PreviousHalf] AS [Date - Master].[Financial Calendar].LEAD(-1).UNIQUENAME
MEMBER [HalfName] as [Date - Master].[Financial Calendar].[Season Half].CURRENTMEMBER.VALUE
SELECT {[HalfName]} ON COLUMNS ,
{[CurrentHalf],NextHalf,PreviousHalf} ON ROWS
FROM [Sales and Stock]
WHERE (Filter([Date - Master].[DateKey].Members,[Date - Master].[DateKey].MemberValue = (format(now(),"dd/MM/yyyy"))))
But that still didn't work.
When you define MEMBER expressions as you have, it infers you are creating them on the [Measures] dimension, so the full name of your [HalfName] column is [Measures].[HalfName].
Also, I don't see where SQL/T-SQL come into this, unless you are mistaking your MDX for SQL (they look similar as they share some syntax, but are very different beasts).

Parents of set in MDX

I have a filter that selects a specific date in my date dimension, This will be passed in as a parameter into the MDX query.
Filter([Date Dimension].[Calendar Year Hierarchy].[Actual Date].members,
[Date Dimension].[Actual Date].CurrentMember.Properties( "Name" ) = '2011-09-01 00:00:00.000')
I would now like to select the weeks and/or months in the hierarchy above that.
[Date Dimension].[Calendar Year Hierarchy].[Month]
[Date Dimension].[Calendar Year Hierarchy].[Calendar Week]
I have tried several functions without much luck such as .Parent and DrillupLevel
I could be using them wrong or in the wrong spot,
thanks for the help
You could use the function GENERATE to get all ascendants:
Generate
(
{Filter([Date Dimension].[Calendar Year Hierarchy].[Actual Date].members,
[Date Dimension].[Actual Date].CurrentMember.Properties( "Name" ) =
'2011-09-01 00:00:00.000')},
{Ascendants([Date Dimension].[Calendar Year Hierarchy].CurrentMember)}
)
Query using Adventure Works:
Select
{[Measures].[Internet Sales Amount]} On Columns,
{Generate(
{Filter([Date].[Calendar].[Date].members,[Date].[Calendar].CurrentMember.Properties("Name") = 'April 1, 2004')},
{Ascendants([Date].[Calendar].CurrentMember)})} On Rows
From [Adventure Works]
If you know the level you're looking for you can use MDX Ancestor function instead of parent:
Ancestor([Date Dimension].[Calendar Year Hierarchy].currentmember,
[Date Dimension].[Calendar Year Hierarchy].[Month])
If no, it's fine using parent function. Note, using properties is not the quickest method to filter (for very large sets).
Why not using to StrToMember MDX function ?
StrToMember( ... here build your member with a string ... )
or if you can edit you mdx directly creating the statement directly with the help of a string builder ?
so the answer i have at the moment is
Filter([Date Dimension].[Calendar Year Hierarchy].[Actual
Date].members, [Date Dimension].[Actual
Date].CurrentMember.Properties( "Name" ) = '2011-09-01 00:00:00.000')
.item(0).parent
using the .item[0] to get the item in the set
and the .parent to get that items parent (in my case i am actually calling it 3 times)
if anyone has any better ideas would love to here them.
You can use STRTOSET and for each input parameter replace ] with ].Parent, this way you will have set of parents.

Check if level in any dimension hierarchy is [Foo]

In my Date Dimension I have 2 hierarchies:
[Year - Week - Date] and [Year - Month - Date]
I want to check in a Cube Calculation if the current level of the Date Dimension is [Date] (the lowest level) or something higher.
How can I achieve this?
Background: I need this to calculate how many working days there were in a period, for an employee.
I currently have this code (untested) that should do the trick for 1 hierarchy, but I guess this will fail when users are using the [Year - Week - Date] hierarchy.
CASE WHEN
[Date].[Year - Month - Date].CURRENTMEMBER.Level
IS
[Date].[Year - Month - Date].[Date]
THEN
//at day level,
//if there is any duration booked, this is a working day
IIF([Measures].[Duration] = 0,0,1)
ELSE
//at higher than day level,
//count days
COUNT(
// where duration > 0 (employee work day)
FILTER(
Descendants([Date].[Year - Month - Date].CURRENTMEMBER, [Date].[Year - Month - Date].[Date]),
[Measures].[Duration] > 0
)
)
END
tl;dr how do I make the above code also work for [Year - Week - Date] hierarchy in the cleanest way possible.
Let's assume the hierarchy (aka attribute) [Date].[Date] exists. If this is the case you can simplify :
COUNT(
FILTER( Existing [Date].[Date].members, [Measures].[Duration] > 0 )
)
The Existing will force to apply an autoexists on the [Date] dimension. This is mainly a performance improvement as it's avoid to evaluate (fact-vise) all tuples.
Once the former examples is clear, we can merge it with your version for the fastest solution (no need for the first iif) :
COUNT(
FILTER( Existing
Descendants([Date].[Year - Month - Date].CURRENTMEMBER, [Date].[Year - Month - Date].[Date],self)
, [Measures].[Duration] > 0 )
)
Further improvements may be possible adding a new measure with a different aggregation type or adding an iif to change which of the two hierarchies is used for descendants (e.g. the one where the currentmember and the defaulmember is not equal)
If you are looking for the cleanest way to calculate how many working days there were in a period, you have to emulate the behavior of regular measure. Otherwise you will get error or bad data in the case of a multiselect on [Date]. In addition, it is desirable to get rid of the Count(Filter(...)) expression to keep the block computation mode (see Optimizing Count(Filter(...)) expressions in MDX). To do this, follow these steps:
Go to the data source view.
Create a new named calculation next to the [Duration] column (in the same fact table).
Column name is "Working days", expression is "null".
Create a new regular measure based on "Working days" column. Aggregation function is Sum.
Write in the MDX script:
(
[Date].[Date].[Date].Members,
[Measures].[Working days]
) = Iif( [Measures].[Duration] > 0, 1, null );
IsLeaf() will tell you if a member is at the bottom level.
Look at SCOPE commands in your calculation script, I do something similar for my YMD calender and my YWD calendar:
CREATE MEMBER CurrentCube.Measures.Example AS NULL //Dummy will be calc'd later
SCOPE (DESCENDANTS([Date].[Calender Y M D],,AFTER));
Measures.Example = 1; //Fill in for monthly calcs
END SCOPE
SCOPE (DESCENDANTS([Date].[Calender Y W D],,AFTER));
Measures.Example = 2; //Fill in for weekly calcs
END SCOPE
The syntax with the ,,AFTER is to exclude the All member if I remember rightly, I'm trying to dif the link up but can't find it. Alternatively, if the calculation works well with the ALL member, just use SCOPE([Date].[Calender Y W D])