When calculating the average sales per day, I have the following measure for NumOfDays:
NumOfDays = IF (
[Sales Amount] > 0;
COUNTROWS ( Date )
)
What this is doing is removing the number of days for those dates when there are no sales.
Thus, I have the following visual:
As you can see, the total is wrong.
This is due to the fact that the database has more years than those shown in the matrix.
How can I define the granularity for "day" when calculating NumOfDays?
That is, how can I count the rows for those days with sales only?
Thanks!
I recommend two things:
Use CALCULATE() instead of IF, which is the proper DAX way of defining measures with filters
Use DISTINCTCOUNT() instead of COUNTROWS(), to ensure you never run into double counting (in case your data ever becomes more granular)
This calculation may work - but you may need to specify the actual date column inside your Date table.
NumOfDays = CALCULATE(DISTINCTCOUNT(Date[Date]),FILTER(SalesTable,[Sales Amount] > 0))
If there is more to the problem, let me know what exactly you are expecting to see in your matrix.
Related
I have a dataset of patients visiting several categories(SPECIALISM) of a hospital. A visit lasts a couple of hours each day. Each row in my dataset represents an hour that they are present for a certain hospital specialism.
Input
I want to calculate for each hour of the day, the number of patients that are present on average, per specialism, I used the following code (measure):
daggem = AVERAGEX(values('Date'[Date]),[distinctpat])
with distinctpat being a distinct count of patient IDs
This gives me almost the desired result, but the tales of the graph are too heavy (it shows an average of 1 patient during the night, but this 1 patient was there only on 1 specific day, normally it is zero. But the average, as I calculated, it does not include all other nights when there were zero patients. So I would like to obtain an average that is much lower (and more correct)
Output
You probably need an extra table with all the days and times. Based on the reports, you will be able to find the hours without visits
Here is an example of how to create a Date table with hours; Add relationship and use in calculation.
DatesWithHours =
var Dates = CALENDAR("2021-01-01 00:00:00", "2021-01-03 00:00:00")
var DatesHour =
GENERATE(Dates, (ADDCOLUMNS(GENERATESERIES(1,12,1),"Hours", [Date] + TIME([Value],0,0))))
return
DatesHour
That's the problem with AVERAGEX, it ignores blanks. Try a simple division instead.
daggem =
DIVIDE (
COUNTROWS ( TargetTable ),
COUNTROWS ( Dates )
)
I have calculated the next measure that provides the TOTALYTD in the previous year:
It is working as expected. For dates before 01/07/2006, I do not have any value in my second table. However, if I change the formula using a variable, I'm getting this result:
The calculation is performed in the same year (2006). I have been trying to understand the context (kind of new with Dax), but I have not understood this result yet.
When you store a calculation in a variable, it becomes a constant, and can't be re-calculated. That's why DATEDD in your second measure has no effect.
As a good practice, break your calculations into multiple measures. It allows you to re-use them, and makes your code more readable and maintainable. For example:
Sales Amount = SUM(InternetSales[SalesAmount])
Sales YTD = TOTALYTD( [Sales Amount], Calendario[Date])
Sales YTD LY = CALCULATE( [Sales YTD], PREVIOUSYEAR( Calendario[Date]))
I need to calculate headcount while keeping the measure sliceable by any dimension connected to the fact table. Given the nature of my tables and model, what I need to do is a point in time calculation on a Slowly Changing Dimension Type 2.
I managed to make it work using the function KEEPFITLERS, but I need a more scalable function that wouldn't require me to list all the dimensions I want to slice by.
Here is my PowerBI file with sample data: https://gofile.io/d/smS2Hr
Here is a simplified sketch (image) of my model: https://ibb.co/fQYpsdx
Background:
The first measure I am calculating is the number of Employees at the Start of the Period (Employees SoP). If the end-user selects in PowerBI the whole month of January 2020, the Start of the Period is Jan 1st, 2020. Hence, "Employees SoP" for the month of Jan 2020 will give the number of employees on Jan 1st, 2020.
The formula below calculates the correct values for Employees SoP:
Employees SoP =
VAR MinDate = MIN ( 'Date'[Date]) //Mininum date selected by end-user in PowerBI
VAR Result =
CALCULATE (
DISTINCTCOUNT(Fact[EmployeeId]),
FILTER(ALL('Fact'), 'Fact'[EffectiveStartDate] <= MinDate
&& IF(ISBLANK('Fact'[EffectiveEndDate]), date(2050,1,1), Fact[EffectiveEndDate]) > MinDate
))
RETURN
Result
The problem with the formula above is that, because of the ALL function, the measure is not sliceable by any dimension, i.e., Pay Class and Employment Status (the same number repeats itself).
Results:
Hence, I created this other measure using KEEPFILTERS, and it works perfectly.
Employees SoP KEEPFITLERS =
VAR MinDate = MIN ( 'Date'[Date]) //Mininum date selected by end-user in PowerBI
VAR Result =
CALCULATE (
DISTINCTCOUNT(Fact[EmployeeId]),
FILTER(ALL('Fact'), 'Fact'[EffectiveStartDate] <= MinDate
&& IF(ISBLANK('Fact'[EffectiveEndDate]), date(2050,1,1), Fact[EffectiveEndDate]) > MinDate
), KEEPFILTERS(PayClass), KEEPFILTERS(EmploymentStatus))
RETURN
Result
The problem with this formula is that I have to list all the dimensions I want to slice by ( e.g., PayClass, EmploymentStatus) inside the DAX formula. This is not very scalable.
I did some experimenting with REMOVEFILTERS but it looks like it does not work with DirectQuery for now, so it wouldn't solve my production problem. Link:
https://learn.microsoft.com/en-us/dax/removefilters-function-dax
QUESTION:
How can I write this measure using an alternative to KEEPFILTERS with which I wouldn't have to list each dimension I want to slice by?
Thank you!
I just managed to solve my problem. I made both relationships to the Dates table "inactive". With that, I could remove the "ALL" function in the DAX formula and now it not only calculates the correct values, but it also slices nicely. I will have to use the USERELATIONSHIP function to calculate more complex measures but, in most of the cases, this simple solution works like a charm.
Employees SoP without ALL =
VAR MinDate = MIN ( 'Date'[Date]) //Mininum date selected by end-user in PowerBI
VAR Result =
CALCULATE (
DISTINCTCOUNT(Fact[EmployeeId]),
FILTER('Fact', 'Fact'[EffectiveStartDate] <= MinDate
&& IF(ISBLANK('Fact'[EffectiveEndDate]), date(2050,1,1), Fact[EffectiveEndDate]) > MinDate
))
RETURN
Result
I have the simple dataset as below:
I need to permit summing the DistanceTraveled column in a "Measure" given date filters selected, and date order, to allow a cumulative total. The data model is dead simple as it only have one date dimension:
My DAX for the measure is:
Measure = CALCULATE(SUM(ActivityReport[DistanceTraveled]), FILTER(Timestamp,Timestamp[Timestamp] <= MAX(Timestamp[Timestamp])))
I know I must be missing something simple, how can I create a cumulative total given the filtered and increasing Timestamps for column DistanceTraveled?
I think you forgot to include all dates, Try this..
Measure = CALCULATE(
SUM(ActivityReport[DistanceTraveled]),
FILTER(ALL('Timestamp'[Timestamp]),
Timestamp[Timestamp] <= MAX(Timestamp[Timestamp])
)
)
What I ended up doing:
Measure = CALCULATE(
SUM(ActivityReport[DistanceTraveled]),
FILTER(ALLSELECTED(ActivityReport),
ActivityReport[Timestamp] <= MAX(ActivityReport[Timestamp])
)
)
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
)