Combining two calculated measures and using the combination result in MDX - ssas

I am creating two different calculated measure and I want to use the result of both
calculated measure in one query from a same cube.
One of the calculated measure created is -
With Member [Measures].[VenueSalesCost]
as
(
[Measures].[Amount - Reporting Currency]
)
Select [Measures].[VenueSalesCost]
on columns
from [Project accounting cube]
where
[Chart of accounts].[Main account name].&[Venue Hire Costs]
and the second is --
With Member [Measures].[VenueSalesAmount]
as (
[Measures].[Amount - Reporting Currency]
)
Select [Measures].[VenueSalesAmount]
on columns
from [Project accounting cube]
where
[Chart of accounts].[Main account name].&[Rental of Venue]
Now i want to use both the measures in my query.please let me know how to combine the two measure.

Just move the WHERE condition of the different queries into the defining tuple of the calculated measures:
With Member [Measures].[VenueSalesCost]
as
(
[Chart of accounts].[Main account name].&[Venue Hire Costs],
[Measures].[Amount - Reporting Currency]
)
Member [Measures].[VenueSalesAmount]
as
(
[Chart of accounts].[Main account name].&[Rental of Venue],
[Measures].[Amount - Reporting Currency]
)
Member [Measures].[new Measure]
as
[Measures].[VenueSalesCost] - [Measures].[VenueSalesAmount]
Select {
[Measures].[VenueSalesCost],
[Measures].[VenueSalesAmount],
[Measures].[new Measure]
}
on columns
from [Project accounting cube]

Related

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 - Running Sum over months limited to an interval

I have a query that after some sweating and some swearing works
WITH
MEMBER [Measures].[m_active] AS ([Measures].[CardCount], [Operation].[Code].[ACTIVATION])
MEMBER [Measures].[m_inactive] AS ([Measures].[CardCount], [Operation].[Code].[DEACTIVATION])
MEMBER [Measures].[p_active] AS
SUM(
[Calendar.YMD].[2016].[January]:[Calendar.YMD].CurrentMember,
[Measures].[m_active]
)
MEMBER [Measures].[p_inactive] AS
SUM(
[Calendar.YMD].[2016].[January]:[Calendar.YMD].CurrentMember,
[Measures].[m_inactive]
)
MEMBER [Measures].[tot_active] AS (
SUM({[Calendar.YMD].[2010].Children}.Item(0):[Calendar.YMD].CurrentMember, [Measures].[m_active]) -
SUM({[Calendar.YMD].[2010].Children}.Item(0):[Calendar.YMD].CurrentMember, [Measures].[m_inactive])
)
MEMBER [Measures].[p_tot_active] AS
SUM(
[Calendar.YMD].[2016].[January]:[Calendar.YMD].CurrentMember,
[Measures].[tot_active]
)
SELECT
{[Measures].[m_active], [Measures].[p_active], [Measures].[m_inactive], [Measures].[p_inactive], [Measures].[tot_active], [Measures].[p_tot_active]} ON COLUMNS,
NonEmptyCrossJoin(
{Descendants([Calendar.YMD].[2016].[January]:[Calendar.YMD].[2017].[August], [Calendar.YMD].[Month])},
{Descendants([CardStatus.Description].[All CardStatus.Descriptions], [CardStatus.Description].[Description])}
) on ROWS
FROM [Cube]
What I obtain is a table that for each months show the activation and deactivation relative to that month, the accumulated activations relative to the period considered (starting from 1 January 2016 and ending 1 August 2017) and the total active cards from the beginning of time (january 2010) until the end time interval.
This interval is parametrized and the day are to be considered, with this query all the activations made in august are considered even the ones made after the 1st.
I try to make some modifications like this.
WITH
MEMBER [Measures].[m_active] AS ([Measures].[CardCount], [Operation].[Code].[ACTIVATION])
MEMBER [Measures].[m_inactive] AS ([Measures].[CardCount], [Operation].[Code].[DEACTIVATION])
MEMBER [Measures].[p_active] AS
SUM(
[Calendar.YMD].[2016].[January].[1]:[Calendar.YMD].CurrentMember,
[Measures].[m_active]
)
MEMBER [Measures].[p_inactive] AS
SUM(
[Calendar.YMD].[2016].[January].[1]:[Calendar.YMD].CurrentMember,
[Measures].[m_inactive]
)
MEMBER [Measures].[tot_active] AS (
SUM({[Calendar.YMD].[2010].[January].Children}.Item(0):[Calendar.YMD].CurrentMember, [Measures].[m_active]) -
SUM({[Calendar.YMD].[2010].[January].Children}.Item(0):[Calendar.YMD].CurrentMember, [Measures].[m_inactive])
)
MEMBER [Measures].[p_tot_active] AS
SUM(
[Calendar.YMD].[2016].[January].[1]:[Calendar.YMD].CurrentMember,
[Measures].[tot_active]
)
SELECT
{[Measures].[m_active], [Measures].[p_active], [Measures].[m_inactive], [Measures].[p_inactive], [Measures].[tot_active], [Measures].[p_tot_active]} ON COLUMNS,
NonEmptyCrossJoin(
{Descendants([Calendar.YMD].[2016].[January]:[Calendar.YMD].[2017].[August], [Calendar.YMD].[Month])},
{Descendants([CardStatus.Description].[All CardStatus.Descriptions], [CardStatus.Description].[Description])}
) on ROWS
FROM [Cube]
But I get this error on the relative fields:
#ERR: mondrian.olap.fun.MondrianEvaluationException: Members must belong to the same level
How can i solve this? Thanks.

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

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.

MDX: Mixed row aggregation types within single period column time aggregation

I am trying wrap my head around a way to produce the following result from a Mondrian cube.
Sample Values:
Year Month Sales
---- ----- -----
2015 Jan 10
2015 Feb 11
2015 Mar 12
2015 Apr 10
2015 May 11
2015 Jun 12
Jan-Mar 2015 | Apr-Jun 2015
---------------------------------------------------
Sales Sum | 33 | 33
Sales Average | 11 | 11
The current MDX is something like this:
with
member [Date].[JAN-MAR] as Aggregate([Date].[2015].[3].lag(2):[Date].[2015].[3])
member [Date].[APR-JUN] as Aggregate([Date].[2015].[6].lag(2):[Date].[2015].[6])
member [Measures].[Sales Sum] as Sum([Date].CurrentMember, [Measures].[Sales])
member [Measures].[Sales Average] as Avg([Date].CurrentMember, [Measures].[Sales])
select
{[Date].[JAN-MAR],
[Date].[APR-JUN]} on columns,
{[Measures].[Sales Sum],
[Measures].[Sales Average]} on rows
from [Cube]
The question is how can I get a row to specify an aggregate to use for the current column period aggregation?
Update (17 Aug 2018)
I think I have found a solution, before I get into that I think I should give more background into the scenario. We are using Mondrian to provide some financial reports. Due to the complexity of the reports combined with the fact that end users must be able to create them we have created our own mini reporting tool.
One of the most common report types is measures on rows and columns with various date aggregations e.g. Three Month Rolling Average / Financial Year to Date etc all based on a report parameter date selection offset.
The complexity comes in where for the same column they want different rows to aggregate differently. An example would be the Financial Year to Date column, some rows measures must be summed, some must be averaged and some must return the closing balance.
I haven't found an easy want to model this in the cube yet :/
However I found a way to get it to work by mistake that seems relevantly robust and is also fast. As it turns out Mondrian does not validate member attributes, i.e. you can declare and reference whatever member attributes you want. This has turned out to provide an easy way to can get access to the correct date slice and perform whatever aggregate I want e.g:
with
member [Date].[JAN-MAR] as Aggregate([Date].[2015].[3].lag(2):[Date].[2015].[3]), START_MONTH_MEMBER='[Date].[2015].[1]', END_MONTH_MEMBER='[Date].[2015].[3]'
member [Date].[APR-JUN] as Aggregate([Date].[2015].[6].lag(2):[Date].[2015].[6]), START_MONTH_MEMBER='[Date].[2015].[4]', END_MONTH_MEMBER='[Date].[2015].[6]'
member [Measures].[Sales Sum] as Sum([Date].CurrentMember, [Measures].[Sales])
member [Measures].[Sales Average] as Avg(StrToMember([Date].CurrentMember.Properties('START_MONTH_MEMBER')):StrToMember([Date].CurrentMember.Properties('END_MONTH_MEMBER')), [Measures].[Sales])
select
{[Date].[JAN-MAR],
[Date].[APR-JUN]} on columns,
{[Measures].[Sales Sum],
[Measures].[Sales Average]} on rows
from [Cube]
So far this works well. One thing that doesn't work is I cannot get StrToSet to work. In theory you should be able to declare a set in the with member property and then use the in the measure.
StrToMember(([Date].CurrentMember.Properties('MONTH_RANGE_SET'))
So this what I have working for now, would love some feedback on that?
This is a bit time consuming, but should work:
with
member [Date].[JAN-MAR] as Aggregate([Date].[2015].[3].lag(2):[Date].[2015].[3])
member [Date].[APR-JUN] as Aggregate([Date].[2015].[6].lag(2):[Date].[2015].[6])
member [Measures].[Sales Sum] as Sum([Date].CurrentMember, [Measures].[Sales])
member [measures].yearvalues as [Date].currentmember.member_value
member [Measures].[Sales Average] as
AVG
(
StrToSet(
"[Date].[2015].&[" +
CASE
LEFT(measures.yearvalues, 3)
WHEN "JAN" THEN 1
WHEN "APR" THEN 4 END +
"]:[Date].[2015].&[" +
CASE
RIGHT(measures.yearvalues, 3)
WHEN "MAR" THEN 3
WHEN "JUN" THEN 5 END +
"]"
)
,
[Measures].[Sales]
),
format_string = "#.##"
select
{[Date].[JAN-MAR],
[Date].[APR-JUN]} on columns
{[Measures].[Sales Sum],
[Measures].[Sales Average]} on columns
from [Cube]
Far from ideal but best I can do at the moment:
WITH
SET [JAN-MAR] AS
[Date].[Calendar].[Month].&[2006]&[3].Lag(2)
:
[Date].[Calendar].[Month].&[2006]&[3]
SET [APR-JUN] AS
[Date].[Calendar].[Month].&[2006]&[6].Lag(2)
:
[Date].[Calendar].[Month].&[2006]&[6]
MEMBER [Date].[Calendar].[JAN-MAR] AS
Aggregate([JAN-MAR])
MEMBER [Date].[Calendar].[APR-JUN] AS
Aggregate([APR-JUN])
MEMBER [Measures].[Sales Sum] AS
[Measures].[Internet Sales Amount]
MEMBER [Measures].[Sales Average] AS
[Measures].[Internet Sales Amount] / [JAN-MAR].Count
SELECT
{
[Date].[Calendar].[JAN-MAR]
,[Date].[Calendar].[APR-JUN]
} ON 0
,{
[Measures].[Sales Sum]
,[Measures].[Sales Average]
} ON 1
FROM [Adventure Works];
So I thought maybe I'd try adding the custom members to an unrelated dimension (effectively make it a utility dimension). This works ok but extracting the count of number of related months is still proving difficult. This is the current effort:
WITH
SET [JAN-MAR] AS
[Date].[Calendar].[Month].&[2006]&[3].Lag(2)
:
[Date].[Calendar].[Month].&[2006]&[3]
SET [APR-JUN] AS
[Date].[Calendar].[Month].&[2006]&[6].Lag(2)
:
[Date].[Calendar].[Month].&[2006]&[6]
MEMBER [Product].[Category].[JAN-MAR] AS
Aggregate
(
[JAN-MAR]
,[Product].[Category].[All Products]
)
MEMBER [Product].[Category].[APR-JUN] AS
Aggregate
(
[APR-JUN]
,[Product].[Category].[All Products]
)
MEMBER [Measures].[Sales Sum] AS
[Measures].[Internet Sales Amount]
MEMBER [Measures].[Sales Avg] AS
[Measures].[Internet Sales Amount]
/
NonEmpty
(
[Date].[Calendar].[Month].MEMBERS
,(
[Product].[Category].CurrentMember
,[Measures].[Internet Sales Amount]
)
).Count //<<<<currently returning 72 rather than 3
SELECT
{
[Product].[Category].[JAN-MAR]
,[Product].[Category].[APR-JUN]
} ON 0
,{
[Measures].[Sales Sum]
,[Measures].[Sales Avg]
} ON 1
FROM [Adventure Works];
We can see that it is getting divided by 72 rather than 3:
Problem as I currently see it is trying to get hold of the number of related months to each of the custom members after they have been aggregated - here is a simplified example of what I mean:
WITH
SET [JAN-MAR] AS
//<< set of 3 months
[Date].[Calendar].[Month].&[2006]&[1]
:
[Date].[Calendar].[Month].&[2006]&[3]
MEMBER [Product].[Category].[JAN-MAR] AS
//<< chuck on unconnected hierarchy
Aggregate
(
[JAN-MAR]
,[Product].[Category].[All Products]
)
MEMBER [Measures].[countMonthsRelatedToMember] AS //<<attempt to count mths related to [Product].[Category].[JAN-MAR]
NonEmpty
(
[Date].[Calendar].[Month].MEMBERS
,(
[Product].[Category].CurrentMember
,[Measures].[Internet Sales Amount]
)
).Count //<<<<currently returning 72 rather than 3
SELECT
[Product].[Category].[JAN-MAR] ON 0
,[Measures].[countMonthsRelatedToMember] ON 1
FROM [Adventure Works];

Using intersect with 2 large sets to get the distinct count - MDX

I have a calculated member which represents an active customer. That would be the following;
WITH MEMBER [Measures].[Active Customers] AS
Count ( nonempty( Filter (
( [Customer].[Customer Key].Members, [Measures].[Turnover] ),
[Measures].[Turnover] > 0
) ) )
This works great, when I want to get active customers in the current period and previous ones, as I get my time dimension, and use the CurrentMember, CurrentMember.PrevMember and CurrentMember with the Lag function in order to get customers who were active in previous periods.
My problem is when I want to get the count of customers, who are common in different members. Say I want to get customers who are active in the current period, and NOT in the previous period. Or another case, active in current, and active in previous. Because of this, I would need to use the INTERSECT function, and my customer dimension has 4 million records. This is already a subset of 9 million records.
So when checking for a customer who is active in 2 consecutive periods, I do this (The Active Previous Period, and Active Current Period is basically the calculated member above, however with CurrentMember and CurrentMember.PrevMember) :
set [Previous Active Customers Set] AS
Filter (
( [Customer].[Customer Key].Members, [Measures].[Active Previous Period] ),
[Measures].[Active Previous Period] > 0
)
set [Current Active Customers Set] AS
Filter (
( [Customer].[Customer Key].Members, [Measures].[Active Current Period] ),
[Measures].[Active Current Period] > 0
)
member [Measures].[Active 2 consecutive periods] as
count(INTERSECT([Current Active Customers Set],[Previous Active Customers Set]) )
This takes forever. Is there anyway to improve, or go around this performance problem of using the INTERSECT with large sets? Or maybe optimizations on the MDX query? I tried always using a subset of my customers dimension, but this only reduced the number of records to less than 4 million - so it's still large. Any help would be appreciated!
I would assume you can speed this up if you avoid using named sets and calculated members as far as possible.
One step towards this would be as follows: Create a new fact table with foreign keys just to your customer and time dimension, and add a record to it if a customer was active on that day. Build a measure group, let's say "activeCustomers" based on this table, just using "count" as the measure. But make this invisible, as we do not need it.
Then, you can replace
count( nonempty( Filter (
( [Customer].[Customer Key].Members, [Measures].[Turnover] ),
[Measures].[Turnover] > 0
) ) )
with
count( Exists(
[Customer].[Customer Key].Members,
<state your time selection here>,
"activeCustomers"
) )
Exists should be more efficient than Filter.
Another optimization approach could be the observation that instead of intersecting two sets generated via Filter, you could define one set with a more complex filter, avoiding that AS is looping along the customers twice, and then intersecting the results:
set [Active Customers Set] AS
Filter (
( [Customer].[Customer Key].Members, [Measures].[Active Previous Period] ),
[Measures].[Active Previous Period] > 0
AND
[Measures].[Active Current Period] > 0
)