I have to count something in a strange way, and it works in most cases -- both at leaves and at higher levels of aggregation across multiple dimensions. But it doesn't give correctly aggregated values for one specific dimension.
What I have at the moment is ...
CREATE MEMBER CURRENTCUBE.[Measures].[Active Commitments]
AS NULL,
FORMAT_STRING = '#,#',
VISIBLE = 1;
SCOPE (DESCENDANTS([Date Dimension].[Fiscal Year Hierarchy],,AFTER));
[Measures].[Active Commitments] =
iif([Constituent Activity].[Type].currentMember.Properties("Name")="Correspondence",
sum(([Commitment Dates].[Start Date], NULL: [Date Dimension].[Fiscal Year Hierarchy]), [Measures].[Commitment Count]),
sum(([Commitment Dates].[First Funded Date], NULL: [Date Dimension].[Fiscal Year Hierarchy]), [Measures].[Commitment Count]))
- sum(([Commitment Dates].[Stop Date],[Commitment].[Was Commitment Ever Active].[Sometime Active], NULL: [Date Dimension].[Fiscal Year Hierarchy]), [Measures].[Commitment Count]);
END SCOPE;
SCOPE (DESCENDANTS([Date Dimension].[Fiscal Year Hierarchy],,AFTER));
<Similar to above>
As you can see, the complexity is that one type of "commitment" commences at the [Start Date] and others commence at the [First Funded Date].
This fails whenever multiple members of [Constituent Activity] are selected because in such cases the use of currentMember in the SCOPE statement is invalid. For example, the following MDX executes successfully but outputs #Error --
select
[Measures].[Active Commitments] on columns
,[Date Dimension].[Fiscal Year Hierarchy].[Fiscal Year].&[2011\12] on rows
from Compass3
where
{[Constituent Activity].[Description].[XYZ]
,[Constituent Activity].[Description].[ABC]}
I think what I need to encode within the SCOPE statement is the recursive ...
if a single member of [Constituent Activity] is current
then use the calc as defined above
else use [Measures].[Active Commitments] = sum(all selected members of [Constituent Activity], [Measures].[Active Commitments])
... but how would I write that?
Do you have control all the way back to the data warehouse/data source view? Can you add a calculated field to your fact table, so you have [Commitment Active Date] at the cell level? Then you could do much simpler counts in the cube.
I have found that enforcing business rules and doing business calculations in the data warehouse is more efficient and easier in the long run.
Related
I've build a MDX calc member that give me the year-to-date (YTD) for budget, however if the user selects multiple months, it returns the total for year. Which I believe is CurrentMember function, but how do it I get the max from the set?
Aggregate(
PeriodsToDate(
[Date].[Fiscal].[Fiscal Year]
,[Date].[Fiscal].CurrentMember
)
,[Measures].[Budget]
)
So when we have a month slicer to select the month, if the end-user selects more then 1 month, then the CurrentMember fails and the parent is used, so the Full Year (FY) is used.
It might be very late to answer this question but hopefully someone else can benefit with the answer.
for this particualr problem you have to create a dynamic set and apply scope to that. check the below MDX.
dynamic set : existing PeriodsToDate(Date].[Fiscal].[Fiscal Year],[Date].
[Fiscal].CurrentMember)
calcualted member : Aggregate( PeriodsToDate( [Date].[Fiscal].[Fiscal Year]
,[Date].[Fiscal].CurrentMember
)
,[Measures].[Budget]
)
apply scope to it scope (Date].[Fiscal].[Fiscal Year],,[Measures].[Budget])
this = aggregate (([dynamic set],],[Measures].[Budget])
end scope
this way u can select a date range without any problem
Kind Regards
mah
Trying to figure out what the default member adds to this scipt
([DateTool].[Aggregation].[Previous Month]) =
iif(
([DateTool].[Aggregation].DefaultMember, ParallelPeriod(dim_RPT_period].[Yr-Qtr-Month].[RPT Period Month],1,[dim_RPT_period].[Yr-Qtr-Month].currentmember)) = null,
NULL,
([DateTool].[Aggregation].DefaultMember,ParallelPeriod([dim_RPT_period].[Yr-Qtr-Month].[RPT Period Month],1,[dim_RPT_period].[Yr-Qtr-Month].currentmember))
);
This is from a utility dimension. Calculation script.
I get the IIF, and I get the ParallelPeriod.
But what effect does "(DefaultMember, ParallelPeriod)" have?
It looks like it used to avoid infinite recursion. This technique is used in this kind of dynamic calculations.
Let's say we run some MDX script with WHERE [DateTool].[Aggregation].[Previous Month].
Server takes this calculation from your formula (without [DateTool].[Aggregation].DefaultMember), it uses ParallelPeriod as usual, but than it needs [DateTool].[Aggregation].[Previous Month] as a part of tuple with other dimensions (our WHERE filter), so it takes from this formula again and again...
So we always need to have some fixed member to avoid infinite recursion.
That is my understanding, please correct if it's somewhere or totally wrong.
My understanding is that the calculated member is built to have values only when the slicer has any member from [dim_RPT_period].[Yr-Qtr-Month].[RPT Period Month] level. This is my opinion imitates the ISCROSSFILTERED functionality of DAX.
The member is built such that [DateTool].[Aggregation].[Previous Month] would hold value only when
the slicer has a member from [dim_RPT_period].[Yr-Qtr-Month].[RPT Period Month]
[DateTool].[Aggregation].DefaultMember is as good as [DateTool].[Aggregation].[ALL]
It is as good as leaving out [DateTool].[Aggregation] hierarchy from the query
If slicer does not have a member from [dim_RPT_period].[Yr-Qtr-Month].[RPT Period Month],
then [dim_RPT_period].[Yr-Qtr-Month].currentmember is as good as [dim_RPT_period].[Yr-Qtr-Month].[ALL]
The previous member in this case(which is returned by ParallelPeriod function) is undefined and hence, NULL would be returned.
If slicer has the member, a non null member would be returned.
To further illustrate upon this:
(Please read through the comments)
([DateTool].[Aggregation].[Previous Month]) =
iif(
(
[DateTool].[Aggregation].[ALL],
ParallelPeriod([dim_RPT_period].[Yr-Qtr-Month].[RPT Period Month],1,[dim_RPT_period].[Yr-Qtr-Month].currentmember)
) //If a member from dim_RPT_period].[Yr-Qtr-Month].[RPT Period Month] level is not in slicer then it would evaluate to NULL
= null,
NULL, //In that case the previous month should evaluate to NULL
//Otherwise, it should give the "previous month"
([DateTool].[Aggregation].[ALL],
ParallelPeriod([dim_RPT_period].[Yr-Qtr-Month].[RPT Period Month],1,[dim_RPT_period].[Yr-Qtr-Month].currentmember))
);
My situation is as following:
This is a Powerpivot solution developed in Excel 2013 (32-bit).
I got a transaction table containing transactions with an amount, a category and a posting date. What I would like to to is to present a number of different calculations depending on the time frame.
Sum of amount of current day of import (all the transations with the latest posting date available).
Sum of amount Month-to-date (the current month of the latest transaction)
Sum of amount same period last month (Month-to-date minus one month)
Sum of amount last month (the totals for whole last month)
So, idea is to create a "Current day" measure as a stand point for all the other measures.
[Current day] = LASTDATE('TransactionTable'[Posting Date])
Before summarizing things I wanted to create measures that would represent the start and end date for each period (to display in the report and to make easier measures), this is where I run into trouble.
[First day of current month] = STARTOFMONTH([Current Day])
Gives me the error: "A function 'CALCULATE' has been used in a True/False expression that is used as a table filter expression. This is not allowed."
And with this I would like to end up with something like this for current month:
[Sum of amount current month] = CALCULATE(SUM('Transactiontable'[Amount]);DATESBETWEEN('DateTable'[Date]; [First day of current month];[Current day]))
And this for previous month total:
[First day of previous month] = DATEADD([First day of current month];-1;MONTH)
[Last day of previous month] = EOMONTH([Current day];-1)
CALCULATE(SUM('Transactiontable'[Amount]);DATESBETWEEN('DateTable'[Date]; [First day of previous month]; [Last day of previous month]))
It feels like I am not using the measures the "right" way... Basically I want to create dynamic measures that will change the timeframe depending on what the latest posting date is in the transaction table. Is this the way to go at all?
Thanks guys,
First you need to use ALL()
You were pretty close - the trick to getting [CurrentDate] right is use of the ALL() function. This handy function overrides any filter conditions you have.
So let's look at your [CurrentDate] measure that uses LASTDATE('TransactionTable'[Posting Date]). If your pivot table has months as row labels, this will happen:
The row context alters the output of [CurrentDate]. Not what we want. So you need to override the filter condition, like this.
[CurrentDate] = CALCULATE(LASTDATE(TransactionTable[Posting Date])
,ALL(TransactionTable)
)
Then you need FILTER()
Then to sum the amount for [CurrentDay] we do this:
[SumAmountCurrentDay] = CALCULATE([SumAmount]
,FILTER(TransactionTable
,TransactionTable[Posting Date]=[CurrentDay]
)
)
We need to use FILTER() because it's a more complicated criteria than CALCULATE can handle by default. FILTER() explicitly tells CALCULATE() which table it needs to filter on - although it might be obvious to us, it isn't to PowerPivot.
Here are the rest of the formulas you need, of varying complexity but mostly reusing functions you've listed above, plus ALL() and FILTER().
[FirstDayOfCurrentMonth]
=CALCULATE(STARTOFMONTH(TransactionTable[Posting Date])
,ALL(TransactionTable)
,FILTER(TransactionTable
,TransactionTable[Posting Date]=[CurrentDay]
)
)
[SumAmountCurrentMonth]
=CALCULATE([SumAmount]
,DATESBETWEEN(DateTable[Date]
,[FirstDayOfCurrentMonth]
,[CurrentDay]
)
)
[FirstDayOfPrevMonth]
=CALCULATE(STARTOFMONTH(TransactionTable[Posting Date])
,ALL(TransactionTable)
,FILTER(TransactionTable
,TransactionTable[Posting Date]=
CALCULATE(dateadd(LASTDATE(TransactionTable[Posting Date])
,-1
,month
)
,ALL(TransactionTable)
)
)
)
[LastDayOfPrevMonth]
=CALCULATE(ENDOFMONTH(TransactionTable[Posting Date])
,ALL(TransactionTable)
,FILTER(TransactionTable
,TransactionTable[Posting Date]=
CALCULATE(dateadd(LASTDATE(TransactionTable[Posting Date])
,-1
,month
)
,ALL(TransactionTable)
)
)
)
SumAmountPrevMonth
=CALCULATE([SumAmount]
,DATESBETWEEN(DateTable[Date]
,[FirstDayOfPrevMonth]
,[LastDayOfPrevMonth]
)
)
I looked at this topic, Calculating the number of days in a time dimension node - with Grand Total, but can't seem to get it.
I have a Time Dimension; [Invoice Date].
I want to count the number of Work Days in that dimension for a specified time period. I'm new to MDX.
Here's what I have.
Count(
Descendants(
[Invoice Date].CurrentMember,
[Invoice Date].[Work Date].[Work Date]
)
)
I'm getting a cube error now.
An easy way to implement this reliably would be to create a physical measure "Day Count". To do this, create a new measure group on the Date dimension table, and define "Day Count" as the Count. On the dimension usage tab, make sure you set a relationship from this measure group to the Invoice Date cube dimension and not the other dimensions.
I have a fact table which stores for each record an init_year and end_year as integers, which refer to the year range in which the record is valid.
In which way I can design a MDX query to select my measures (count) for each year, in order to have a trend of my measures over year?
THANKS
I'm not sure this should be done in MDX.
This sort of thing is usually calculated in the fact tables (linked to a dimension table of all available years), and a new measure is created. No calculation would be done in MDX; you'd just display the new measure.
Having said that, I've just Googled "MDX count start end date" and found www.purplefrogsystems.com/blog/2013/04/mdx-between-start-date-and-end-date which suggests you use the LINKMEMBER function. Their example code was...
AGGREGATE(
{NULL:LINKMEMBER([DATE].[Calendar].CURRENTMEMBER
,[START DATE].[Calendar])}
* {LINKMEMBER([DATE].[Calendar].CURRENTMEMBER
, [END DATE].[Calendar]):NULL}
, [Measures].[Project COUNT])
...or...
AGGREGATE({NULL:[DATE].[Calendar].CURRENTMEMBER}
, [Measures].[Project COUNT])
...but it needs careful reading!