DAX Cumulative VAMI Return - ssas

Here's a simplified version of my model:
I have P/L (profit and loss) data at the daily level for several funds and several securities. To calculate the % return is easy - it's the P/L divided by the opening AUM (assets under management). But each month the AUM changes significantly due to investor contributions. So, to get a YTD return %, I need to calculate cumulative returns, for which the formula is (see here):
YtdReturn =
PRODUCTX ( MonthlyReturnTable, DIVIDE ( MonthlyReturn, OpeningAUM ) +1 ) -1
The difficulty is that my P/L is at the daily level. I successfully created this:
CompoundReturn:=
PRODUCTX (
ADDCOLUMNS (
VALUES ( tblDates[MonthYearNumber] ),
"PnL Total1", CALCULATE ( SUM ( PnL[TradingPnL] ) + SUM ( PnL[InterestDividendsPnL] ) ),
"Month_Opening_AUM1", CALCULATE ( VALUES ( Daily_AUM[MonthOpeningAUM] ) )
),
DIVIDE ( [PnL Total1], [Month_Opening_AUM1] ) + 1
)
- 1
This works well:
However, I want to do this on a running YTD basis. I'm having trouble setting the "inner" table to YTD. I tried surrounding the VALUES() with a CALCULATETABLE() to filter by YTD, but didn't work:
CompoundReturn :=
PRODUCTX (
ADDCOLUMNS (
CALCULATETABLE (
VALUES ( tblDates[MonthYearNumber] ),
DATESYTD ( tblDates[Date] )
),
"PnL Total1", CALCULATE ( SUM ( PnL[TradingPnL] ) + SUM ( PnL[InterestDividendsPnL] ) ),
"Month_Opening_AUM1", CALCULATE ( VALUES ( Daily_AUM[MonthOpeningAUM] ) )
),
DIVIDE ( [PnL Total1], [Month_Opening_AUM1] ) + 1
)
- 1
The result in Excel is not a running return, but individual:
Any ideas? Thanks!
Note: All code formatted with daxformatter.com

Figured it out with the help of a friend. I needed to put the CALCULATETABLE outside the ADDCOLUMNS:
CompoundReturn :=
PRODUCTX (
CALCULATETABLE (
ADDCOLUMNS (
VALUES ( tblDates[MonthYearNumber] ),
"PnL Total1", CALCULATE ( SUM ( PnL[TradingPnL] ) + SUM ( PnL[InterestDividendsPnL] ) ),
"Month_Opening_AUM1", CALCULATE ( VALUES ( Daily_AUM[MonthOpeningAUM] ) )
),
DATESYTD ( tblDates[Date] )
),
DIVIDE ( [PnL Total1], [Month_Opening_AUM1] ) + 1
)
- 1

Related

DAX : optimize measure in SSAS 2012 tabular model

-I use SSAS 2012 SP4 tabular version.
The cube contains 2 facts tables and each one uses the same dimension tables (=7 dimension tables).
There is no relation defined between 2 fact tables.
-The following measure is setup in Fact2 table:
Measure1 :=
IF (
SUM ( Fact1[ColumnA] ) = 0,
BLANK (),
IF (
SUM ( Fact2[ColumnB] ) > 0,
SUM ( Fact1[ColumnA] ) / SUM ( Fact2[ColumnB] ),
99
)
)
My Excel report is very long to refresh when I display this measure and several attributes.
-When I active a profiler trace I can see that the time spend in the Formula Engine is 80%.
I have tried to rewrite the query with using the function DIVIDE() like this :
Measure1 := DIVIDE(sum(Fact1[ColumnA])/sum(Fact2[ColumnB]),99)
In this case the report is fast and query duration is better. But as I have removed the IF function I don't check any more "if sum(Fact1[ColumnA])=0"
It is possible to refactor this DAX formula in order to improve performance. And keeping the check "IF sum(Fact1[ColumnA])=0 THEN BLANK()" ?
Thanks a lot for your help
Em
Sure, try this:
Measure 1 :=
VAR SUMA =
SUM ( 'Fact1'[ColumnA] )
VAR SUMB =
SUM ( 'Fact2'[ColumnB] )
VAR QUOT =
DIVIDE ( SUM ( 'Fact1'[ColumnA] ), SUM ( 'Fact2'[ColumnB] ) )
RETURN
SWITCH ( TRUE (), SUMA = 0, BLANK (), SUMB > 0, QUOT, 99 )
If you can't use Variables in your measures, try this:
Measure1 :=
SWITCH (
TRUE (),
SUM ( 'Fact1'[ColumnA] ) = 0, BLANK (),
SUM ( 'Fact2'[ColumnB] ) > 0, DIVIDE ( SUM ( 'Fact1'[ColumnA] ), SUM ( 'Fact2'[ColumnB] ) ),
99
)
Another method would be to create a calculated column like so:
result := DIVIDE ( SUM ( 'Fact1'[ColumnA] ), SUM ( 'Fact2'[ColumnB] )
)
Then, write a measure against it like this:
Measure1 :=
SWITCH ( TRUE (), [result] = 0, BLANK (), [result] > 0, [result], 99 )
I haven't tested either of these so I am not sure how their performance will be.
Hope it helps!

Ordering a complex set

I've been playing with a script of Chris Webb's found here: http://cwebbbi.wordpress.com/2007/06/25/advanced-ranking-and-dynamically-generated-named-sets-in-mdx/
The adapted script is this:
WITH
SET MyMonths AS
TopPercent
(
[Date].[Calendar].[Month].MEMBERS
,20
,[Measures].[Reseller Sales Amount]
)
SET MyEmployees AS
[Employee].[Employee].[Employee].MEMBERS
SET MyMonthsWithEmployeesSets AS
Generate
(
MyMonths
,Union
(
{[Date].[Calendar].CurrentMember}
,StrToSet
("
Intersect({},
{TopCount(MyEmployees, 10, ([Measures].[Reseller Sales Amount],[Date]. [Calendar].CurrentMember))
as EmployeeSet"
+
Cstr(MyMonths.CurrentOrdinal)
+ "})"
)
)
)
MEMBER [Employee].[Employee].[RestOfEmployees] AS
Aggregate
(
Except
(
MyEmployees
,StrToSet
(
"EmployeeSet" + Cstr(Rank([Date].[Calendar].CurrentMember,MyMonths))
)
)
)
MEMBER [Measures].[EmployeeRank] AS
Rank
(
[Employee].[Employee].CurrentMember
,StrToSet
(
"EmployeeSet" + Cstr(Rank([Date].[Calendar].CurrentMember,MyMonths))
)
)
SELECT
{
[Measures].[EmployeeRank]
,[Measures].[Reseller Sales Amount]
} ON 0
,Hierarchize
(
Union
(
Filter
(
MyMonthsWithEmployeesSets * MyEmployees //<<<HERE<<<<
,
[Measures].[EmployeeRank] >= 1
)
,{
MyMonthsWithEmployeesSets * [Employee].[Employee].[RestOfEmployees]
}
)
) ON 1
FROM [Adventure Works];
How do I ORDER the output so that each set of ten employees is in order 1 to 10, with the MEMBER called RestOfEmployees always found in position 11 i.e. it should follow the member ranked 10 ?
The temptation is to add the ORDER function at the point marked HERE i.e. that line will become :
MyMonthsWithEmployeesSets * ORDER(MyEmployees, [Measures].[EmployeeRank])
Doing that results in the following error message:
The dimension '[EmployeeSet0]' was not found in the cube when the string, [EmployeeSet0], was parsed.
I believe this is because the measure EmployeeRank uses the inline sets created during the generate function.
If you redefine EmployeeRank to be 11 for RestOfEmployees, you can just add that member to the set that is the first argument to Filter, and than apply Order, as it will sort after position 1 to 10:
WITH
SET MyMonths AS
TopPercent
(
[Date].[Calendar].[Month].MEMBERS
,20
,[Measures].[Reseller Sales Amount]
)
SET MyEmployees AS
[Employee].[Employee].[Employee].MEMBERS
SET MyMonthsWithEmployeesSets AS
Generate
(
MyMonths
,Union
(
{[Date].[Calendar].CurrentMember}
,StrToSet
("
Intersect({},
{TopCount(MyEmployees, 10, ([Measures].[Reseller Sales Amount],[Date]. [Calendar].CurrentMember))
as EmployeeSet"
+
Cstr(MyMonths.CurrentOrdinal)
+ "})"
)
)
)
MEMBER [Employee].[Employee].[RestOfEmployees] AS
Aggregate
(
Except
(
MyEmployees
,StrToSet
(
"EmployeeSet" + Cstr(Rank([Date].[Calendar].CurrentMember,MyMonths))
)
)
)
MEMBER [Measures].[EmployeeRank] AS
IIF([Employee].[Employee].CurrentMember IS [Employee].[Employee].[RestOfEmployees],
11,
Rank
(
[Employee].[Employee].CurrentMember
,StrToSet
(
"EmployeeSet" + Cstr(Rank([Date].[Calendar].CurrentMember,MyMonths))
)
)
)
SELECT
{
[Measures].[EmployeeRank]
,[Measures].[Reseller Sales Amount]
} ON 0
,
Order(
Filter
(
MyMonthsWithEmployeesSets
* UNION(MyEmployees, {[Employee].[Employee].[RestOfEmployees]})
,
[Measures].[EmployeeRank] >= 1
), [Measures].[EmployeeRank]
)
ON 1
FROM [Adventure Works];

Measure lacking context

I am struggling to force the measure CountTopPromos to be contextual.
Currently it is calculating a count of all the tuples in TopX. Against the version of AdWrks that I am running this is 14.
How do I force a context, of the current year, onto the measure CountTopPromos
WITH
SET FullSet AS
NonEmpty
(
[Date].[Calendar].[Calendar Year].MEMBERS
*
[Promotion].[Promotion].MEMBERS
,[Measures].[Reseller Order Count]
)
SET TopX AS
Generate
(
[Date].[Calendar].[Calendar Year].MEMBERS
,TopPercent
(
[Date].[Calendar].CurrentMember
*
Extract
(
FullSet
,[Promotion].[Promotion]
)
,90
,[Measures].[Reseller Order Count]
)
)
MEMBER [Measures].[CountTopPromos] AS
Count(TopX) //<<<<<<<<<<<< CONTEXT LACKING HERE <<<<<<<
SELECT
NON EMPTY
{[Measures].[CountTopPromos]} ON 0
,{TopX} ON 1
FROM [Adventure Works];
Currently it returns the following:
I'd like CountTopPromos to be in the context of the year so the desired output is as follows:
As sets are evaluated before the axes are defined (see my answer to this question), you cannot get row context into the calculation if you use the named set TopX. You could, however, copy its definition into the definition of [Measures].[CountTopPromos], replacing [Date].[Calendar].[Calendar Year].MEMBERS with [Date].[Calendar].CurrentMember:
MEMBER [Measures].[CountTopPromos] AS
Count(
Generate
(
[Date].[Calendar].currentMember
,TopPercent
(
[Date].[Calendar].CurrentMember
*
Extract
(
FullSet
,[Promotion].[Promotion]
)
,90
,[Measures].[Reseller Order Count]
)
)
)
delivers the result you want. And - as the Generate would loop over just one member here - you could omit that as well:
MEMBER [Measures].[CountTopPromos] AS
Count(
TopPercent
(
[Date].[Calendar].CurrentMember
*
Extract
(
FullSet
,[Promotion].[Promotion]
)
,90
,[Measures].[Reseller Order Count]
)
)
and will get the same result.
Another alternative that is quite pretty:
MEMBER [Measures].[CountTopPromos] AS
Count
(
Intersect
(
{
[Date].[Calendar].CurrentMember * [Promotion].[Promotion].MEMBERS
}
,TopX
)
)

SQL to Mimic Excel

I have an finance issue that we are trying to put into a SQLServer 2005 database (default installation). We are doing quarterly comparison from this year to the same quarter last year i.e. (2013Q1 - 2012Q1) / 20132Q1. Can someone write a query to return an ordered list from 1 - 9 with the quarter over quarter as described above?
In data set
QUART REV
2011Q1 6,175,352
2011Q2 6,591,067
2011Q3 6,219,978
2011Q4 6,189,939
2012Q1 7,178,652
2012Q2 6,731,467
2012Q3 6,949,978
2012Q4 6,679,939
2013Q1 6,242,802
2013Q2 6,421,902
2013Q3 6,667,007
2013Q4 6,575,004
Expected output
QUART COMP
1 0.1625
2 0.0213
3 0.1174
4 0.0792
5 -0.1304
6 -0.0460
7 -0.0407
8 -0.0157
Thanks in advance ;-)
I agree with the above comment, it is much easier if you split quart:
create table t
( yr int not null
, qt int not null
, salary int not null
, primary key (yr,qt) )
insert into t (yr,qt,salary)
values (2011,1,6175352)
, (2011,2,6591067)
, (2011,3,6219978)
, (2011,4,6189939)
, (2012,1,7178652)
, (2012,2,6731467)
, (2012,3,6949978)
, (2012,4,6679939)
, (2013,1,6242802)
, (2013,2,6421902)
, (2013,3,6667007)
, (2013,4,6575004)
select row_number() over (order by yr, qt) as quart, comp
from (
select t1.yr, t1.qt
, (1.0*t1.salary - (select salary
from t t2
where t2.yr = t1.yr - 1
and t2.qt = t1.qt)
) / t1.salary comp
from t t1
where t1.yr >= 2012
)
my numbers deviates from yours, I have not investigate why but it should give you a start.
Lot of formatting in a SQL query, but the exercise was fun. Normally, you should elevate formatting (such as rounding) to the application level, but since you're trying to emulate Excel...
/*sample data*/
DECLARE #T TABLE ( Quart CHAR(6), Rev INT )
INSERT INTO #T
( Quart, Rev )
VALUES ( '2011Q1', 6175352 ),
( '2011Q2', 6591067 ),
( '2011Q3', 6219978 ),
( '2011Q4', 6189939 ),
( '2012Q1', 7178652 ),
( '2012Q2', 6731467 ),
( '2012Q3', 6949978 ),
( '2012Q4', 6679939 ),
( '2013Q1', 6242802 ),
( '2013Q2', 6421902 ),
( '2013Q3', 6667007 ),
( '2013Q4', 6575004 );
/*query begins here
cte is used to parse quart column into years & quarters */
WITH cte
AS ( SELECT Yr = CONVERT(SMALLINT, LEFT(Quart, 4))
, Qt = RIGHT(Quart, 1)
, Rev
FROM #T
)
/*join cte to itself to compare last year same quarter
ROW_NUMBER used to get sequential ordering
CONVERT to numeric and rounding to get formatting
*/
SELECT QUART = ROW_NUMBER() OVER (ORDER BY b.Yr
, b.Qt) ,
COMP = CONVERT(NUMERIC(5,4), ROUND((a.Rev-b.Rev*1.0)/ b.Rev, 4))
FROM cte a
JOIN cte b ON b.Qt = a.Qt
AND b.Yr = a.Yr - 1

MDX custom consolidation: consolidate only last level descendants

I'm looking for a elegant MDX expression that sum values only of the elements of last level dimension:
I have a measure M , also I have a hierarchical parent - child dimension U that is non balanced tree:
R -> ( M = R1 + R2 = 157 )
..R1 -> ( M = R11 + R12 = 150 )
...R11 -> ( M=R111 = 100 )
.....R111 -> M=100
...R12 -> M = 50
..R2 -> M = 7
I have a set that contains some elements from this dimension:
S contains R11, R111, R12
Now I need to take, for a U.currentMember the M value (that is, the sum of last level descendants)
I have written this expression, it works but perhaps they are a more elegant way to write it:
with member measures.XX as
sum (
intersect(
[S],
Except(
descendants( [U].currentMember ),
existing( descendants( [U].currentMember ).item(0) )
)
)
,
[M]
)
select
measures.xx on columns
from [CUBE]
where [U].[R]
Note: This MDX dont run:
with member measures.XX as
sum (
intersect(
[S],
descendants( [U].currentMember )
)
,
[M]
)
select
measures.xx on columns
from [CUBE]
where [U].[R]
because return 250 insteat 150.
Right result is 150: R11 + R12 (because R111 is included in R11).
Bad result is: 250: '100' value is taked for twice R11 + R111.
Final Solution:
with member measures.XX as
sum(
intersect (
descendants([U].currentMember,,leaves),
[S]
)
,
[M]
)
select
measures.XX on 0,
descendants( [Unitats].[Unitat].[All] ) on 1
from [C]
Not sure what you want to calculate but let's assume [Member] is the member you want to evaluate :
I'd use the descendants, filter and isLeaf MDX functions :
Sum(
Filter( Descendants( [Member] ), isLeaf(Member_hierarchy.currentmember) )
,[M])
You're adding all descendants including itself that are leafs (no children).