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]
)
)
Related
NB: this is a follow up question from Syntax of MS Access/SQL sub-query including aggregate functions.
I am trying to produce a database to manage maintenance of equipment. I have two tables:
One (Inventory) containing details of each piece of equipment, including Purchase Date and Service Period,
One containing details of work done (WorkDone), including the date the work was carried out (Work Date).
I would like a query that displays the date that it should be next serviced. So far I have:
SELECT Max(NZ(DateAdd('m', i.[Service Period], w.[Work Date]),
DateAdd('m', i.[Service Period], i.[Purchase Date]))
) AS NextServiceDate, i.Equipement
FROM Inventory i LEFT JOIN WorkDone w ON i.ID = w.Equipment
GROUP BY i.Equipement
I would now like to order by NextServiceDate and only show entries where NextServiceDate is in the next week. However adding
HAVING (((Max(Nz(DateAdd('m',i.[Service Period],w.[Work Date]),DateAdd('m',i.[Service Period],i.[Purchase Date]))))<DateAdd('ww',1,Date()))
ORDER BY Max(Nz(DateAdd('m',i.[Service Period],w.[Work Date]),DateAdd('m',i.[Service Period],i.[Purchase Date])));
only shows when the day of the month is less than one week from now (e.g. if it is the 1st today it will show all entries where NextServiceDate occurs in the first 7 days of any month of any year, past or future). For some reason it is only considering the day of the month and not the full date. I don't understand why...
NB: I have a British system so date format is dd-mm-yyyy.
After a cursory review of your code, I'm unsure whether the instances of i.Equipement is a typo (since your JOIN clause refers to a similar field w.Equipment), or whether these two fields are intentionally named differently?
I can't see anything else immediately wrong with your code, but it may be clearer and easier to debug if you were to restructure the code to the following:
SELECT
Max(sub.dat) as NextServiceDate, sub.eqp
FROM
(
SELECT
DateAdd('m',i.[Service Period],Nz(w.[Work Date],i[Purchase Date])) as dat, i.Equipement as eqp
FROM
Inventory i LEFT JOIN WorkDone w ON i.ID = w.Equipment
) AS sub
GROUP BY
sub.eqp
HAVING
Max(sub.dat) < DateAdd('ww',1,Date())
ORDER BY
Max(sub.dat)
Note that the difference in regional date formats will only have an effect when you are specifying literal dates (for example, as criteria), in which case you would need to adhere to the format #mm/dd/yyyy#.
I have a simple powerpivot model with a datetable and a milestone table.
shown in the figure. The milestone table has columns of milestone forecast and actual dates, eventually for six major milestones but two are shown. I am able to summarize (calculated field) the COUNT of forecasted or actual milestone events by week and year. But I cannot see how to also generate a cumulative total (YTD) of these counts - probably missing something that should be obvious.
The two calculated fields that work are:
MS1 YTD Forecast:=CALCULATE(COUNT([Forecast MS1 Date]))
MS1 YTD Actual:=CALCULATE(COUNT([Actual MS1 Date]), USERELATIONSHIP(milestones[Actual MS1 Date],datetbl[Date]))
The pivotchart of this shows
Eventually I would like to create a report showing the progress for each milestone (actual vs forecast) for this project.
I have a partial answer. Added 'helper columns' with a 1 or 0 based on existence of a date. THEN used Javier Guillen's "Running Totals" post (https://javierguillen.wordpress.com/2012/11/28/running-total-techniques-in-dax/) to create the lines.
But I get a syntax error when I attempt to apply the DAX Cumulative pattern to FILTER for valid dates. My measure is:
Cumulative MS1 Actual :=
IF (
MIN ( 'datetbl'[Date] )
<= CALCULATE ( MAX (milestones[Actual MS1 Date] ), ALL (milestones) ),
CALCULATE (
SUM (milestones[MS1 Actual exists] ),
USERELATIONSHIP(milestones[Actual MS1 Date],datetbl[Date]),
FILTER (
ALL ( 'datetbl'[Date] ),
'milestones'[MS1 Actual Date] <= MAX ( 'milestones'[MS1 Actual Date] )
)
)
)
I am getting a semantic error 'column 'MS1 Actual Date' in table milestones cannot be found or may not be used in this expression.
unfortunately I cannot seem to post the updated chart or datamodel
I've been tasked with a rather odd Time intelligence function by my finance group that I'm trying to puzzle out.
I've been asked with creating a measure within our SSAS Cube to allow for seeing previous quarter to date based on how far we are in the current quarter. But instead of seeing a standard idea of days elapsed currently versus days elapsed previously, they would like to see days remaining versus previous days remaining.
What I mean by that is, take 1/22/2015 for example. We have 48 days remaining in our current quarter, which I have by means of a calculated measure. I need to find the corresponding working day from the previous quarter where it is also at 48 days remaining.
At that point I could create a date range with some aggregate functions off of the first date in the previous quarter to the corresponding date found in the above and come up with what they are looking for.
The best idea I've had so far is to possibly do this in the database section itself, by creating a new column that is essentially the calculated number of days remaining but stored. But at that point I'm not sure how to take a calculated measure in SSAS and filter a previous quarter date member to use that property as it were.
Do you have an utility dimensions in your cube? We have one called TimeCalculations. In there we have things such as CurrentValue, MTDValue, PrevEquivMTD, Past7Days .... I think your new logic would fit in with such a dimension.
Here is an example of PrevEquivQTD against AdvWrks that I just had a play with. Guessing this doesn't really help your scenario but I had fun writing it:
WITH
SET [NonEmptyDates] AS
NonEmpty
(
[Date].[Calendar].[Date].MEMBERS
,[Measures].[Internet Sales Amount]
)
SET [LastNonEmptyDate] AS
Tail([NonEmptyDates])
SET [CurrQ] AS
Exists
(
[Date].[Calendar].[Calendar Quarter]
,[LastNonEmptyDate].Item(0)
)
MEMBER [Measures].[pos] AS
Rank
(
[LastNonEmptyDate].Item(0)
,Descendants
(
[CurrQ]
,[Date].[Calendar].[Date]
)
)
MEMBER [Measures].[PrevEquivalentQTD] AS
Sum
(
Head
(
Descendants
(
[CurrQ].ITEM(0).PrevMember
,[Date].[Calendar].[Date]
)
,[Measures].[pos]
)
,[Measures].[Internet Sales Amount]
)
SELECT
{[Measures].[pos],[Measures].[PrevEquivalentQTD]} ON 0
,[LastNonEmptyDate] ON 1
FROM
(
SELECT
[Date].[Calendar].[Date].&[20050111]
:
[Date].[Calendar].[Date].&[20080611] ON 0
FROM [Adventure Works]
);
Your Date is 1/22/2015. You want the Same Date in Previous Quarter which would be 8/22/2015.
If this is what you want, you will have to use MDX function ParallelPeriod as shown in sample below. Please replace it with your own Dimensions and Cube.
Select
ParallelPeriod
(
[Date].[Calendar Date].[Calendar Quarter], -- Level Expression
1, -- Index
[Date].[Calendar Date].[Date].&[20150122] -- Member Expression
) On 0
From [Adventure Works]
If you want the same date in the following quarter, then replace index 1 with -1.
Cheers
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 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.