I want to create a simple percent change formula in power BI. Specifically, I want to evaluate month over month %change in cost. I know that percent change can be defined in different ways, so to be clear this is the formula that I am referring to:
%change = ([current value] - [previous value])/[previous value].
Here is an example in Excel of what I want to achieve:
I cannot find a way to target a specific row in a DAX formula. It seems that power BI only wants to include aggregate values such as sum, max, etc.
As a final note, I know that PowerBI includes a percent change "quick measure". However, the 'Base Value' always requires you to select aggregate measure instead of a single row value.
As Alexis mentioned, there is no concept of referring to a specific row in DAX. It can be a hard notion for people who are used to Excel, but if you want to take advantage of PowerBi, you will have to "unlearn" Excel way of thinking.
To accomplish your goal, you need to do some data modeling first. As a common practice, replace your "Date" column with a proper Calendar table:
Calendar table explained
As a result, you will have a data model in PowerBi that looks something like this:
Once you have such structure in place, DAX is simple:
Current Month Cost = SUM(Expenses[Cost])
Previous Month Cost = CALCULATE( [Current Month Cost], PREVIOUSMONTH(Calendar[Date]))
% Change = DIVIDE( [Current Month Cost] - [Previous Month Cost], [Previous Month Cost])
I used Earlier to get the previous date value for Open
Accum = var previousOpen=CALCULATE(MAX(EOG[Open]),FILTER(EOG,EOG[Date]<EARLIER('EOG'[Date],1))) return Divide(EOG[Open]-previousOpen,previousOpen)+1
Related
Below is the sample dataset
The data has two slicers ( date and category ) shown below
I am writing a DAX Statement to multiply the sum(values) * 10 only if the date range is in the current year 2023.
The StartYear gives the start of the current year, firstD gives the lowest date from the date slicer.
Formula =
var new = sum(Test[Value]) * 10
var startyear = DATE(YEAR(TODAY()),1,1)
var firstD = CALCULATE( MIN( Test[Date]), ALLSELECTED(Test[Date]) )
return if( ISFILTERED(Test[Categories]) && firstD >= startyear, new, 0 )
Now when I filter dates to 2023, the total value should be 2300 but it shows as 0
However the DAX works when I select A or B
If we remove the ISFILTERED function then, it gives wrong value, the expected value is 0 because the start date is in 2022, but it shows 650
let me know if that is the right syntax
It looks like you are not using a separate calendar table to handle this, which you need!
In your very last example you have set your slicer to some time late 2022, but the minimum value of 'Test'[Date] for your selected category is in year 2023. Hint: set the slicer to e.g. 2022-12-14, this will include a 2022-date for Category A in your data.
Your measure behaves exactly how it is supposed to, in other words!
To fix this, you need to do the following:
Create a calendar table in your model, this should contain contiguous dates, which is necessary for the filtering method you want
Establish a relationship between the calendar table and existing Test table.
Use the date column from your new calendar table in your slicer and as date reference in your measure
Exactly how to create a calendar table is thoroughly documented on Google, I recommend you search and find an article or video you understand for implementing this.
Lastly: Your use of ISFILTERED in this measure seems strange, since you mention nowhere the requirement of only showing a number if the column you are testing filtering on is filtered, if that makes sense.. :-) The way you describe your calculation, you only need to check whether the selected date range starts in current year.
I have a fact table with sales data, and I need to calculate the % change month over month. I have tried the following formula:
PreviousMonthSales:= calculate(
SUM('fTable'[Sales];
Parallelperiod( 'Calender'[Date], -1, month)
)
The result that I receive in the pivot table is the same value as the current month. So it seems like something is being calculated, but the result is not different at all from the regular sales column.
The Calender Table is my date table. I have also tried using the functions PreviousMonth and DateAdd, but that has also not worked.
I am not sure if it will make a difference, but I am using Power Pivot in Excel 365, not Power BI.
I currently have a raw data table called Score Table which has three columns: (1) an entity ID, (2) a score, and (3) a date.
I also have a Measure for a single dynamic date (I can't use date slicers for this for reasons that I won't bore you with).
My goal is to have a measure tell me what the last score is before the date indicated by the Measure.
I for some reason am unable to pull this off in DAX. Whenever I try to use Calculate( functions in DAX, I end up only pulling the final date in the 'Score Table' [Date] column (not before the Measure date and not different by ID.
Any help on this would be greatly appreciated.
I still miss some information to give you a specific answer, but something like this should work.
PreviousScore =
CALCULATE(
LASTNONBLANK('Table'[Score])
,FILTER(
ALL('Calendar')
,'Calendar'[Date] < [YourDateMeasure]
)
)
Note that I'm assuming you have a Calendar table to manage the dates (you usually want one of those in your model)
I am getting the following error message when I write the below code:
Value for 'Total Sales'cannot is determined. Either 'Total Sales' does not exist or there is no current row for a column named 'Total Sales'
enter code here
LYSales = CALCULATE([Total Sales],SAMEPERIODLASTYEAR('Date'[Date]))
How do I fix this? I have the Total Sales column with data. It is set to general currency.
Written in this way your formula is not referencing a measure, not a column, also you will need an expression inside calculate.
-- This reference a Measure, which in your case is not defined
LYSales = CALCULATE([Total Sales],SAMEPERIODLASTYEAR('Date'[Date]))
-- you can create it with this formula
Total Sales = SUM('_TableName_'[Total Sales])
--The other way is to use only one formula
LYSales = CALCULATE(SUM('_TableName_'[Total Sales]),SAMEPERIODLASTYEAR('Date'[Date]))
As a note, to use time intelligence functions you need to mark the calendar table as "date table": right click on the table -> "Mark as Date Table"
The calculation looks at the table column as a whole. Your formula uses the value in the current row of the column. So, change it to
LYSales = CALCULATE('Your Table Name'[Total Sales],SAMEPERIODLASTYEAR('Date'[Date]))
How to construct DAX measure to calculate sum of YTD value for specific month?
Here we have FactTable grouped by months. FactTable is filled with both Actual data and Forecast data. The only way to know when Actual end is information in table [Cut of date] in column [End of YTD]. In table [Cut of date] in column [End of YTD] – it is a single value table – we have the interesting chosen month, for which we want to see the calculation of YTD. In our case it is March. FactTable is updated irregularly every month with usually one month delay. There is no way of linking it to time functions like TODAY because of irregular update.
We would like to have a correct value of YTD displayed in yellow Card Visual for the month [End of YTD]. When we click on the slicer on "2018-03" we get almost what we want – correct value of 66 in the yellow Card. However this solution is not automatic. I want to see correct value automatically when the [End of YTD] month changes, in our case to April or then to May. I do not want it done by user.
My desperate effort can be downloaded from file: DAX YTD.pbix
I pursued the deer in various ways:
By using FILTER function in DAX measures. But it seems that the
FILTER function is to harsh. It is applied to fact table first,
selecting only one month, and then calculating YTD value wrongly. So if
there would be any option for forcing order of calculation and filtering, there would
be hope.
I tried SWITCH function to display proper result
for specific month and 0 or null for other months. Although I
succeed in this, I was not able to take advantage of it. When it
came to filtering I was as hopeless as before. BTW I would be able
to make it if SWITCH produced totals at the end of the table, but it
does not. Surprisingly.
I put some hopes in RELATED function to display proper results in the [Cut off date] table. I have not walk out of the fog so far.
I would appreciate your help.
Update before bounty.
Going to higher level. I have introduced a Category column to FactTable. Please download DAX YTD by category.pbix. So filtering gets more complex now. I would like to have correct YTD figures for Apples category.
Did you use the Date column from the Calendar table, instead of the one from FactTable?
If you use the date column from FactTable, when you apply a filter on the date, it will filter on the fact records which is in March, and then do the calculation afterwards, hence the result 33.
If you use the one from Calendar, when you apply a filter on it, it filters the records on Calendar (which you want to show in the chart), so the underlying calculation will still remain intact.
A working example:
Calendar = CALENDAR(DATE(2010, 1, 1), DATE(2020, 12, 31))
I suggest you to change the calculations of the measures to avoid missing values in some cases:
Total = SUM(FactTable[Value])
MTD = TOTALMTD([Total], 'Calendar'[Date])
YTD = TOTALYTD([Total], 'Calendar'[Date])
UPDATE:
It's much clearer to me what you want to achieve now but it still seems an XY problem to me.
I understand that you want to show the dashboard as is so that users do not need to click/input every time to see what they are supposed to see. That's why I don't get why you need to create a new table to store the Cut off date (End of YTD). How is it going to be maintained automatically?
The relative date filtering solution above actually still works in the .pbix file you've shared. If you drag the Date column from the Calendar table to visual level filters for the yellow card and add the relative date filtering, it should work as below:
For the End of YTD visual, you can use the following measure to get the first day of last calendar month, so you don't need to create another table for it:
End of YTD = EOMONTH(TODAY(), -2) + 1
And hopefully this is what you want to achieve:
Updated file for your reference.
UPDATE again:
I think you'll have to write your own YTD calculation instead of using the built-in one, so that you can make use of the cut off date you defined in another table. Here I assume that you have one and only one row in 'Cut off date'[End of YTD]. Note that I've added ALL() to the filter, so that the yellow card remains the same (66) instead of showing blank when some other rows/filters are clicked:
YTD_Special =
CALCULATE(
[Total],
FILTER(
ALL(FactTable),
FactTable[Date] >= DATE(YEAR(VALUES('Cut off date'[End of YTD])), 1, 1) &&
FactTable[Date] <= VALUES('Cut off date'[End of YTD])
)
)
I would resolve this by adding a calculated column to your Calendar table to categorise each row into either "YTD" or "Other", e.g.
Is YTD =
IF (
[Date] >= DATE ( YEAR ( DISTINCT ( 'Cut off date'[End of YTD] ) ), 1, 1 )
&& [Date] <= DISTINCT ( 'Cut off date'[End of YTD] ),
"YTD",
"Other"
)
I would then add the new Is YTD field to the Visual level filters of your Card visual, and choose YTD from the Basic filtering list. The measure shown can be your simple Total measure: SUM(FactTable[Value]).
This is a far more flexible and resuable solution than any specific measure gymnastics. You will not need an explosion of measures to apply the required logic on top of every base measure - they will all just work naturally. You can apply the filter at any level: Visual, Page, Report, or put it in a Slicer for control by the end user.
I prefer to return text results e.g. "YTD" / "Other" (rather than 1/0, True/False or Yes/No), as this allows for easy extension to other requirements e.g. "Prior YTD" (1 Jan 2017 to 1 Mar 2017). It also is clearer when used in visuals.
Actually I shouldn't claim the credit for this design - this roughly follows how Cognos Transformer's Relative Time functionality worked back in the 90s.
I did something like this in my Periodic/YTD report (last sheet): http://ciprianbusila.ro/
I have used the index value of the month selected (range 1-12) and based on this I have created a measure using max function please see the code below:
ACT = var
ACT_periodic=calculate([Value],Scenarios[Scenario]=values(Scenarios[Scenario]))
var max_month=max(Periods[Period Order])
var ACT_YTD=CALCULATE([Value],Scenarios[Scenario]=VALUES(Scenarios[Scenario]),all(Periods[Month]),Periods[Period Order]<=max_month)
var myselection=if(HASONEVALUE(MRD_view[.]),values(MRD_view[.]),"PERIODIC")
return
switch(
true(),
myselection="PERIODIC",ACT_periodic,
myselection="YEAR TO DATE",ACT_YTD,
ACT_periodic
)