MDX calculated measure on dimension value without measure value - mdx

I am new to mdx and SSAS, We are trying to convert our store procedure to mdx query. I have a cube like below:
Fact table:
[Target] (FK),
[Date] (FK),
[Action] (FK),
[Amount] (Measure),
Dim Date:
[DateKey] (pk),
[Date],
[DayOfYear],
[DayofWeek],
[....]
Dim Action: has fourkind of actions (added, removed, connected, ..)
[ID] (PK)
[Name]
Dim Target:
[ID] (PK)
[Name]
I want to create a calculated measure like what we did in t-sql
SELECT ....,
SUM(
CASE
WHEN a.[Action]='added'
THEN DATEDIFF(DAY, a.[Date],GETUTCDATE())
ELSE DATEDIFF(DAY, a.[Date],GETUTCDATE())*-1
END
)/NULLIF( SUM(CASE WHEN a.[Action]='added' THEN 1 ELSE 0 END),0)
AS 'AverageLifespan'
FROM FilterData a
GROUP BY a.[Target]
I have tried following but failed, it only returns 0 ;
With Member [Measures].[LifeSpan] as
CASE
WHEN [Dim Action Types].[Name].CURRENTMEMBER IS [Dim Action Types].[Name].&[added] THEN 1*'datediff("d",[Dim Date].[Date],Now()) '
WHEN [Dim Action Types].[Name].CURRENTMEMBER IS [Dim Action Types].[Name].&[removed] THEN -1*'datediff("d",[Dim Date].[Date],Now()) '
ELSE 0
End
select [Measures].[LifeSpan] on columns,
[Dim Action Targets].[Name].Children on rows
from [OLAP Prep]
-----------output---------------
LifeSpan
tilerecipes/account-news 0
tilerecipes/competitornews 0
tilerecipes/innovation-blog 0
tilerecipes/sales-now 0
tilerecipes/inbox 0
tilerecipes/in-the-news 0
tilerecipes/jobs 0
tilerecipes/l-and-d 0
Tried on below query, still not working (removed the date part, just for testing):
With Member [Measures].[LifeSpan] as
CASE
WHEN [Dim Action Types].[Name].CURRENTMEMBER IS [Dim Action Types]. [Name].&[added] THEN 1
WHEN [Dim Action Types].[Name].CURRENTMEMBER IS [Dim Action Types]. [Name].&[removed] THEN -1
WHEN [Dim Action Types].[Name].CURRENTMEMBER IS [Dim Action Types].[Name].[All] THEN Sum([Dim Action Types].[Name].Children,[Measures].[LifeSpan]) -- this will work.
ELSE 0
End
select [Measures].[LifeSpan] on columns,
[Dim Action Types].[Name].Members on rows
from [OLAP Prep]
--------Output------------
LifeSpan
All 0
added 1
connected 0
disconnected 0
removed -1

There is one thing to remember in MDX : Calculated measures are not aggregated.
When you develop along the [Dim Action Targets].[Name] Axis, the [Dim Action Targets].[Name] default member is used, which is by default [Dim Action Targets].[Name].[All]
If you tried
select [Measures].[LifeSpan] on columns,
[Dim Action Types].[Name].Members on rows
from [OLAP Prep]
You will see your calculated measures behave properly, except for the [Dim Action Types].[Name].[All] Member.
In order for your calculated measure to behave properly on your original request
With Member [Measures].[LifeSpan] as
CASE
WHEN [Dim Action Types].[Name].CURRENTMEMBER IS [Dim Action Types].[Name].&[added] THEN 1*'datediff("d",[Dim Date].[Date],Now()) '
WHEN [Dim Action Types].[Name].CURRENTMEMBER IS [Dim Action Types].[Name].&[removed] THEN -1*'datediff("d",[Dim Date].[Date],Now()) '
WHEN [Dim Action Types].[Name].CURRENTMEMBER IS [Dim Action Types].[Name].[All] THEN Sum([Dim Action Types].[Name].Children,[Measures].[LifeSpan]) -- this will work.
ELSE 0
End
Well, the simplest way would be to create a LifeSpan measure in your cube definition, make it point to your Amount column of your fact table. Let the default behaviour
Now, go to the Calculation tab of the cube definition. Switch to Script mode.
You should see the "CALCULATE" instruction.
CALCULATE;
Scope([Measures].[LifeSpan]);
This = 0; // We zero out the whole thing first
Scope([Dim Date].[Date].Children,[Dim Action Types].[Name].&[added]})
This = datediff("d",[Dim Date].[Date].CURRENTMEMBER,Now())
End Scope;
Scope([Dim Date].[Date].Children,[Dim Action Types].[Name].&[removed]})
This = -datediff("d",[Dim Date].[Date].CURRENTMEMBER,Now())
End Scope;
End Scope;
This measure will aggregate the right way.

You have to use 'MemberValue' like this :
WHEN
[Dim Action Types].[Name].MemberValue IS
[Dim Action Types].[Name].&[added]
THEN
1*'datediff("d",[Dim Date].[Date],Now())

Related

MDX : how to create a 2x2 array with a query, using hard coded values

in MDX I would like to create a select which returns a 2x2 array, filled with hard coded values.
Here is an attempt:
WITH
MEMBER a AS 1
MEMBER b AS 2
SET un AS { a , b }
SELECT { un} ON 0,
[Dim misc].[Gender].[(All)] ON 1
FROM [my cube]
it returns:
but I would like it to return an other row, with other values than 1,2.
You have solved half the problem already. However defining a set is not necessary.
You need to do the following
Use defaultmember,
Use Case
Define a dummy member for the dimension you use.
Instead of Set just define members.
Take a look at the example below based on adventure works.
with
member Column1Row1 as 1
member Column2Row1 as 2
member Column1Row2 as 3
member Column2Row2 as 4
member Column1 as case when [Product].[Product].currentmember is [Product].[Product].defaultmember then Column1Row1 else Column1Row2 end
member Column2 as case when [Product].[Product].currentmember is [Product].[Product].defaultmember then Column2Row1 else Column2Row2 end
member [Product].[Product].[Row2]
as [Product].[Product].defaultmember
select
{Column1,Column2} on 0,
{
[Product].[Product].defaultmember,
[Product].[Product].[Row2]}
on 1
from
[Adventure Works]
Result

Where Clause using another Dimension Value

I'm trying to create a Calculated Member in my cube with where clause but couldn't figure how to achieve the proper result.
I created a calculated member "Outlook" using the below code to display only Forecast values.
CREATE MEMBER CURRENTCUBE.[Measures].[Outlook]
AS SUM(([Source Profile].[Source Profile Hierarchy].CurrentMember,
[Source Profile].[Profile Level01].&[Outlook]),
[Measures].[USD Amount]),
FORMAT_STRING = "#,##0;(#,##0)",
VISIBLE = 1 , DISPLAY_FOLDER = 'USD' , ASSOCIATED_MEASURE_GROUP = 'CARS';
Cube Result
Now I would like to filter the results dynamically based on another hidden dimension "Current_Month". This dimension always has current financial period value and it's corresponding outlook profile
Year_Month Outlook_Profile
2015010 10 + 2
Expected result should be "Outlook" measure showing value based on Current_Month dimension, which is '10 + 2' and rest of them should be 0
Expected result
Just to explain the requirement in SQL terms, I would like to achieve the below in MDX
Where Fact.Source_Profile=Dimension.Source_Profile
instead of
Where Fact.Source_Profile='10 + 2'
I'm not sure how to achieve this in Where Clause or by another means. I could see examples of hard coding values, like year.&[2015] but haven't seen one using dynamic values.
I found a solution myself and thought of sharing the same. Used StrToMember function to pass hidden dimension's member as a variable here.
CREATE MEMBER CURRENTCUBE.[Measures].[Outlook]
AS (
Sum
(
(
[Source Profile].[Source Profile Hierarchy].CurrentMember,
strtomember("[Source Profile].[Source Name].&[" + [Outlook Profile].[Outlook Profile].&[1].Member_Caption + "]")
)
,[Measures].[USD Amount]
)
),
FORMAT_STRING = "#,##0;(#,##0)",
VISIBLE = 1 , DISPLAY_FOLDER = 'USD' , ASSOCIATED_MEASURE_GROUP = 'CARS' ;

MDX Query to Filter by Date Dimensions

I am new to MDX queries and am trying to figure out how to filter a result set using date dimensions.
Let's take a cube structured like this (contrived example):
I would like to give the user a list of projects to select, and display the cost of all events that occurred during the selected projects (i.e. between start date and end date). However, the events are not linked to projects.
Using the query:
SELECT NON EMPTY
{
[Measures].[Cost]
}
ON COLUMNS,
NON EMPTY
{
(
[Project Details].[Project].[Project].ALLMEMBERS
* [Project Details].[Start Date].[Start Date].ALLMEMBERS
* [Project Details].[End Date].[End Date].ALLMEMBERS
* [Event Details].[Date of Occurrence].[Date of Occurrence].ALLMEMBERS
)
}
DIMENSION PROPERTIES MEMBER_CAPTION, MEMBER_UNIQUE_NAME
ON ROWS
FROM [Cube]
CELL PROPERTIES VALUE, BACK_COLOR, FORE_COLOR, FORMATTED_VALUE, FORMAT_STRING, FONT_NAME, FONT_SIZE, FONT_FLAGS
I can get a list of items like this:
Project Start Date End Date Date of Occurrence Cost
------------------------------------------------------------------
Project 1 01-Jan-15 31-Jan-15 27-Dec-14 750
Project 1 01-Jan-15 31-Jan-15 01-Jan-15 680
Project 1 01-Jan-15 31-Jan-15 02-Jan-15 320
Project 1 01-Jan-15 31-Jan-15 03-Jan-15 150
Project 1 01-Jan-15 31-Jan-15 01-Feb-15 700
Project 1 01-Jan-15 31-Jan-15 05-Feb-15 175
If I run the query for Project 1 only, it should exclude the first event and last 2 events.
Would the best approach be to use a WHERE or FILTER? And because these are dimensions and not measures, how would I do a comparison of WHERE [Date of Occurrence] BETWEEN [Start Date] AND [End Date]?
Any help is much appreciated.
I would try something like this:
WITH MEMBER [Measures].[Cost in period] AS
IIF(
[Event Details].[Date of Occurrence].CurrentMember.Properties('Key') >=
[Project Details].[Start Date].CurrentMember.Properties('Key') &&
[Event Details].[Date of Occurrence].CurrentMember.Properties('Key') <=
[Project Details].[End Date].CurrentMember.Properties('Key'),
[Measures].[Cost], NULL)
SELECT NON EMPTY
{
[Measures].[Cost in period]
}
ON COLUMNS,
NON EMPTY
{
(
[Project Details].[Project].[Project].ALLMEMBERS
* [Project Details].[Start Date].[Start Date].ALLMEMBERS
* [Project Details].[End Date].[End Date].ALLMEMBERS
* [Event Details].[Date of Occurrence].[Date of Occurrence].ALLMEMBERS
)
}
ON ROWS
FROM [Cube]
Basically, you create a calculated measure which is NULL when the Date of Occurrence lies outsite the Start Date - End Date interval. Thanks to NON EMPTY on the Row members, the data should be filtered out of the result.
If [Event Details] and [Project Details] are role playing dimensions, you can put the LINKMEMBER MDX function to use to help you. Also, I am assuming you would be using some sort of front end(maybeSSRS) to give the user the freedom to choose the start and end dates(as parameters or calendar control). In that case, they will enter the MDX query as strings. STRTOMEMBER function converts those string to members.
Using LINKMEMBER, once I generate a set of dates, I am using AGGREGATE function to get the aggregated value of measure for this set of dates.
with set [Start Date] as
linkmember(STRTOMEMBER('[Project Details].[Start Date].[Start Date].&[01/01/2014]'), [Event Details].[Date of Occurrence])
set [End Date] as
linkmember(STRTOMEMBER('[Project Details].[End Date].[End Date].&[01/01/2015]'), [Event Details].[Date of Occurrence])
set ListOfDate as
{[Start Date].item(0):[End Date].item(0)}
member [Measure.NetCost] as
aggregate(ListOfDates, [Measures].[Cost])
SELECT NON EMPTY
{
[Measure.NetCost]
}
ON COLUMNS,
NON EMPTY [Project Details].[Project].[Project].ALLMEMBERS
DIMENSION PROPERTIES MEMBER_CAPTION, MEMBER_UNIQUE_NAME
ON ROWS
FROM [Cube]
CELL PROPERTIES VALUE, BACK_COLOR, FORE_COLOR, FORMATTED_VALUE, FORMAT_STRING, FONT_NAME, FONT_SIZE, FONT_FLAGS
DISCLAIMER: As stated, it would work only if the [Event Details] and [Project Details] are role playing dimensions.
I am not sure if this code would work in your scenario, but I have found this function quite handy at times. To read more on LINKMEMBER function, see here.
Not tested. I've not used && before - maybe just the keyword AND would suffice:
SELECT NON EMPTY
{
[Measures].[Cost]
}
ON COLUMNS,
NON EMPTY
{
(
[Project Details].[Project].[Project].ALLMEMBERS
* [Project Details].[Start Date].[Start Date].ALLMEMBERS
* [Project Details].[End Date].[End Date].ALLMEMBERS
* [Event Details].[Date of Occurrence].[Date of Occurrence].ALLMEMBERS
)
}
HAVING [Event Details].[Date of Occurrence].CurrentMember.MEMBERVALUE >=
[Project Details].[Start Date].CurrentMember.MEMBERVALUE
&& //<< OR IS THIS JUST "AND"?
[Event Details].[Date of Occurrence].CurrentMember.MEMBERVALUE <=
[Project Details].[End Date].CurrentMember.MEMBERVALUE
ON ROWS
FROM [Cube]

calculate percentage of individual categories in MDX

I want to calculate percentage of individual Categories, Here is my mdx code.
WITH
MEMBER [Measures].[Individual_Total] AS ([DIM RATING STRINGS].[LABEL]*[Measures].AGG_RATING Count])
SELECT
NONEMPTY {
[Measures].[AGG_RATING Count],[Measures].[Individual_Total]
} ONColumns,
([DIM STRUCTURE].[PARENT CODE].&[M01]&[M]:[DIM STRUCTURE].[PARENT CODE].&[M11]&[M],
[DIM TAILORING].[TAILORING_LABEL].[TAILORING_LABEL],
{[DIM RATING STRINGS].[LABEL].[LABEL],[DIM RATING STRINGS].[LABEL]}
) onrows
FROM [Cube]
Here is the output
In this output we have 4 categories like ""External Drivers ,stretegy,Business operation and governance.
I need to calculate percentage of different color with in the same category.
For example if we take "External Drivers" then Calculation should be like
amber = 15/28 * 100, green = 5/28/*100 etc because 28 is the sum of external drivers.
Please tell me how to do this thing in mdx.
thanks
Here you can compare with my solution, it will give you the percent of the parent.
with
member [Measures].[Percent of parent] as
([Measures].[Order Quantity]) /
([Product].[Product Categories].currentmember.parent,
[Measures].[Order Quantity])
,format_string = "percent"
SELECT
{([Measures].[Order Quantity]),
([Measures].[Percent of parent])} ON COLUMNS,
{[Product].[Product Categories].[Category].&[3]} *
{[Product].[Subcategory].[Subcategory].Members} *
{[Product].[Style].[Style].Members} *
{[Product].[Product].members}
ON ROWS
FROM [Cube]
I don´t know if i read your dimensions correctly but maybe your member should look something like:
with member [Measures].[Percent] as
[Measures].[AGG_RATING Count] /
([DIM RATING STRINGS].[LABEL].CURRENTMEMBER.PARENT,
[Measures].[AGG_RATING Count])
, format_string = "percent"

Running total only covering range of cells with data

Using the illustrated mockup
(Note not all DimB members show so the total for DimA is larger than the sum of the displayed DimB, ignore this):
Query is showing (months,revenue) on 0, (dima,dimb) on 1 from cube
I would like some assistance in creating the calculated member that would calculate the running total across "Months" here (not a real time dimension).
Earlier i was using this one, but it was wrong on so many levels:
[Measures].[Accumulated Revenue] =
IIF(
([DimMonths].[Months].CurrentMember,[Measures].[Revenue]) = 0
AND ([DimMonths].[Months].CurrentMember.NextMember,[Measures].[Revenue]) = 0
,
IIF(
AGGREGATE({
[DimMonths].[Months].CurrentMember :
[DimMonths].[Months].Parent.LastChild
},[Measures].[Revenue]) = 0
,
NULL
,
Aggregate( {
[DimMonths].[Months].Parent.FirstChild :
[DimMonths].[Months].CurrentMember.PrevMember
}
,[Measures].[Revenue])
)
,
Aggregate( {
[DimMonths].[Months].Parent.FirstChild :
[DimMonths].[Months].CurrentMember
}
,[Measures].[Revenue])
)
Sounds like a job for a "scoped assignment". Basically, using a scoped assignment, you can overwrite the value of your calculated measure along the [Member_DimA_01] slice so that these values represent a running total instead of a sum of children.
Here's a good tutorial from Chris Webb on scoped assignments to help get you started...
Edit: here's a template for the running total calculation...
WITH
SET [Months] AS
{
[Date].[Calendar Month].&[2011 - Jan]
:
[Date].[Calendar Month].&[2011 - Dec]
}
MEMBER [Measures].[Running Total] AS
SUM(
{
[Date].[Calendar Hierarchy].[Calendar Month].&[2011 - Jan]
:
[Date].[Calendar Hierarchy].CurrentMember
}
,[Measures].[Revenue]
)
SELECT
NON EMPTY{
[Months]
} ON 0,
NON EMPTY{
[DimA].[Member].Allmembers *
[DimB].[Member].Allmembers
} ON 1
FROM
[<<cube name>>]
WHERE
[Measures].[Revenue Running Total]