Calculate average of data at different levels by year - powerbi

I have the following Data :
I want to achieve a solution where, when I filter year, it returns me the average of Goodwill of that year and the previous year.
So for my year filter 2017: Average of Goodwill in 2017,2016
year filter 2016: Average of Goodwill in 2016,2015
.... and so on
The year is in General format (NOT Date format) ..
Expected OUTPUT Values:

Not sure what you have tried (or how familiar you are with Power BI/DAX), but you will most likely need to use a combination of DIVIDE, CALCULATE, and ALL. The DIVIDE function isn't super necessary, but it is a great habit to get into as it catches errors. Combining the CALCULATE and ALL will allow you to take the sum for the selected year and the prior year.
What I would do is this:
Goodwill - 2yr Avg =
VAR MaxSelectedYear = MAX([Year])
VAR PriorYear = MaxSelectedYear - 1
VAR MinYearInData = MINX(ALL(Data), [Year])
RETURN
DIVIDE(
CALCULATE(SUM([Goodwill]), FILTER(ALL(Data[Year]), [Year] = MaxSelectedYear))
+
CALCULATE(SUM([Goodwill]), FILTER(ALL(Data[Year]), [Year] = PriorYear))
,
IF(PriorYear < MinYearInData, 1, 2),
BLANK()
)
The IF statement at the end will catch when you are looking at the first year, so that the sum is only divided by 1 instead of 2. The sum will only be 1 year of data since when you filter the Data table to the prior year, there will be no data.

Maybe something like this?
My Average =
IF(HASONEVALUE(Data[Year]);
DIVIDE(
CALCULATE(SUM(Data[Goodwill]);FILTER(ALL(Data[Year]);Data[Year]>=SELECTEDVALUE(Data[Year])-1 && Data[Year]<=SELECTEDVALUE(Data[Year])))
;2);
BLANK()
)
HASONEVALUE, just to identify if my current scope only has 1 year selected for the calculation to be applied.
Than getting the value for the current year and previous year with FILTER and SELECTEDVALUE
I am hardcoding the division by two, but you can adjust it depending on your dataset and purpose.

Related

Create New Column containing value based on conditions on date and hour

I have a table in my power BI with the following fields :
Preview of the data:
The column "platform" has 3 possible values : application, shop, website
"day" is of type Date
"hour" is of type "Date/Time" (same information as "day" + has the hour)
I added a measure to calculate the conversion_rate (orders/visits):
conversion_rate = DIVIDE(SUM(Table[orders]), SUM(Table[visits]))
Then I calculated for every day the conversion_rate from 7 days ago (to be able to compare them):
conversion_rate_7_j = CALCULATE(Table[conversion_rate],
DATEADD(Table[day],-7,DAY)
)
Now my data looks like this:
What I want to do is calculate the conversion rate from 7 days ago but for the same hour.
However I couldn't find a function that substracts field of type Date/Time while taking in consideration the hour.
A solution I thought of is to calculate orders and visits -7 days same hour separately and then divide them to have the conversion rate -7 days same hour:
orders_7_j_hourly =
VAR h = Table[hour] - 7
VAR p = Table[platform]
Return CALCULATE(
MAX(Table[orders]),
Table,
Table[hour] = h,
Table[platform] = p
)
Since my data is grouped by hour (Date/Time) and platform,
And since sometimes for a certain hour I have values for the platform = "application" but not "shop",
My function did not work especially that I am using MAX, this associated the number of orders to the wrong platform.
Can you please help ?
Sample data : https://ufile.io/y1blqgqn
Datetime values are stored in units of days. Thus you can simply shift hour by 7 in your measure.
conversion_rate prev_week =
VAR CurrHour = SELECTEDVALUE ( Table1[hour] )
RETURN
CALCULATE (
[conversion_rate],
ALL ( Table1[day] ),
Table1[hour] = CurrHour - 7
)
Sample results:
Did you try to use HOUR function ??
conversion_rate_7_hour = CALCULATE( [conversion_rate],
FILTER( ALL(Table),
SELECTEDVALUE(Table[day]) - 7 = Table[day]
&& HOUR(SELECTEDVALUE(Table[hour]) - 7) = HOUR( Table[hour])
))
When we put Table[hour] to visualization it should work.
Ps. best pratice => if your refer to measures in your calculations,do not include the table prefix
You can create an additional column called hour in your dataset
Once you have that, you bring the hours in the viz, the following measure can give you what you want
convRate-7 = CALCULATE([convRate],DATEADD('Table'[day],-7,DAY))

HR Employee Count with Slicing by Dimensions - Slowly Changing Dimension

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

How to find day over day change in summarize table taking two columns into account

I have a summarize table that is summed by the Date and Building_Name. I am trying to figure out how to add an increase/ decrease column like my table below. I want to show if the 'total unsigned' has increased from day to day for each building.
I cannot get a formula that will take the previous days total for one building - current days # of total unsigned. Trying to get the forth column for my report. 
I can get it to work if I am just showing day over day change if I am not also trying to add the Building_name to the table.
Unsigned Prev Day =
VAR CurrentDay = SELECTEDVALUE(SummarizeTable[Day Number])
VAR CurrentMonth = SELECTEDVALUE(SummarizeTable[Month Number])
VAR MaxDayNumber = CALCULATE(MAXA(SummarizeTable[Day Number]))
Return SUMX(
FILTER(ALL(SummarizeTable),
IF( CurrentDay = 1,
SummarizeTable[Day Number] = MaxDayNumber && SummarizeTable[Month Number]= CurrentMonth-1,
SummarizeTable[Day Number] = CurrentDay -1)),
[Total Unsigned])
Edit:
Thank you for the help, you definitely put me on the right track. This is the formula I ended up using. Thank you again for the help!
Unsigned Prev Day =
VAR MostRecentDate = MAX ( 'SummarizeTable'[Date] )
RETURN
CALCULATE (
[Total Unsigned],
ALL ( 'SummarizeTable'[Date], 'SummarizeTable'[Day Number], 'SummarizeTable'[Month Number] ),
'SummarizeTable'[Date] = MostRecentDate - 1
)
This assumes that you have or can make a column, 'SummarizeTable'[Date]. If you already have month and day, this should be trivial. This solution takes advantage of the fact that DAX has well-behaved arithmetic on dates.
Additionally, you should look at building a date dimension, rather than doing all of this out of a single table. It will ultimately make your life a lot easier. There are a bunch of good date dimensions out there, but I'm partial to mine.
EDIT: Per discussion in comments the goal is to add this as a calculated column to a data table. The definition above is intended to be used as a measure.
# Increase/ Decrease =
CurrentRowDate = 'SummarizeTable'[Date]
RETURN
CALCULATE (
SUM ( 'SummarizeTable'[Total Unsigned] ),
ALLEXCEPT ( 'SummarizeTable'[Building] ),
'SummarizeTable'[Date] = CurrentRowDate - 1
)
This will add a column to 'SummarizeTable' that has the sum of [Total Unsigned] for the same value of [Building] as is on the current row and with a date 1 less than that on the current row.

Sum Current Month + 2 AND Next Month + 1 and Month After that

I have a metric I need to replicate in DAX for PowerBI and I am not quite sure how to do it.
The basics are this:
Fact Table: Opportunity
Dimensions: Created Date, Closed Date
The metric goes like this, I will just give an example, because I really dont know how to explain it.
SUM OF:
Created in FEB and Closed Date in FEB, MAR, APR
Created in MAR and Closed Date in MAR, APR
Created in APR and Closed in APR
This would happen for each month in the table/matrix.
Seems like I would need some variables something like
Measure =
VAR Month1 = SUM(ClosedOpps) where ClosedDate between CurrentMonth and CurrentMonth + 2
VAR Month2 = SUM(CLosedOpps) where ClosedDate betwwen CurrentMonth + 1 and CurrentMonth + 2
VAR Month3 = SUM(ClosedOpps) where ClosedDate = CurrentMonth + 2
Return Month1 + Month2 + Month3
My understanding is, the Closed Date filter would be the Table/Matrix Visual when I drag the column MonthYear into the visual
EDIT:
Here is a simplified replica of what they are doing in Excel
So The data on the left is the fact table. You can see when the Opps are created, when they are closed. I added in the Created MonthYear and the Closed MonthYear. The Pivot is what they have now in Excel. Dates across the top (Columns) are Created YearMonth, Dates for the Rows are Closed YearMonth.
I need to be able to SUM the numbers inside the of I3:K5 which total 5500 in the example.
UPDATE:
So I have added in a suggested Date Dimension table, Duplicated it (One for Open Date, one for Closed Date) I added a column DateDIM_KEY to each which is just a numerical index. The fact table has these keys, and they are loaded off of the same date range (2013 to 2030). The column ActualValue in the fact table is the column we would SUM.
Here is the updated Fact table sample. I pulled the DateDIM_KEY values directly from the date dimension for those dates.
You need a good date dimension. And you need to have it roleplaying for OpenDate and CloseDate. There are many good date dimensions out there. I like mine.
Assuming that you're putting 'OpenDate'[Month] on an axis label.
Opportunity Value = SUM ( 'Opportunity'[Value] )
MyMeasure iterator =
// start of the month on the current row of a pivot/axis label of a chart
VAR CurrentMonthStart = MIN ( 'OpenDate'[Date] )
// End of the month 2 months out
VAR ThreeMonthsOutEnd = EOMONTH ( CurrentMonthStart, 2 )
// This represents one row per month. You could also use a MonthAndYear type field.
// We will walk through the three open months we care about, and in each will sum
// the value for the opportunities opened in that month, with additional filters.
VAR NextThreeOpenMonths =
CALCULATETABLE (
VALUES ( 'OpenDate'[MonthIndex] ),
ALL ( 'OpenDate' ),
DATESBETWEEN ( 'OpenDate'[Date], CurrentMonthStart, ThreeMonthsOutEnd )
)
RETURN
// Iterate each OpenMonth
SUMX (
NextThreeOpenMonths,
// On each step of the iteration, grab the start of the currently iterated month
VAR IterMonthStart = CALCULATE ( MIN ( 'OpenDate'[Date] ) )
RETURN
CALCULATE (
[Opportunity Value],
// There is date context from visuals we want to ignore:
ALLEXCEPT ( 'OpenDate', 'OpenDate'[MonthIndex] ),
// filter CloseDate to be between the start of the currently iterated
// open month and the originally calculated ThreeMonthsOutEnd. The latter
// is static within the scope of the iteration.
DATESBETWEEN ( 'CloseDate'[Date], IterMonthStart, ThreeMonthsOutEnd )
)
)
Also, while writing the previous iterative approach, I realized we could do the work in a single setfilter:
MyMeasure set =
// MonthIndex is in my date dimension - super useful for arithmetic on dates.
// Read the readme.
VAR C = SELECTEDVALUE ( 'OpenDate'[MonthIndex] ) // want a short name below
// Table literal syntax - two column table, where each parenthesized expression
// forms a row. If it were much more, I'd do something clever with generate, but
// six cases are easy to write by hand.
VAR MonthFilters = {
(C, C),
(C, C+1),
(C, C+2),
(C+1, C+1),
(C+1, C+2),
(C+2, C+2)
}
RETURN
CALCULATE (
[Opportunity Value],
TREATAS ( MonthFilters, 'OpenDate'[MonthIndex], 'CloseDate'[MonthIndex] )
)
I like the latter a lot better, but didn't think of it until after writing the iterative version, so I'm leaving both. Set-based should be better performing.
Edit: some screengrabs I forgot:
Here's the relationship diagram for roleplaying date dim:
And here's the visual in action with both measures:
Best thing to do here is to add a custom column (under edit querys) with the date diff per month. Now you can filter after the column LeadTimeInMonth for you scenarios. If you drag and drop your fields into the visual you can filter by this column.
Date.Month([ClosedDAte])-Date.Month([OpenDate])
I am not sure what you really want to evaluate but if you need need exactly ClosedDate between CurrentMonth and CurrentMonth + 2 you can first evaluate the month from the ClosedDate then the month of today and filter after the result.

Power BI Rolling Total Previous Month DAX

I am working in POWER BI and trying to calculate a DAX expression for the rolling total of the previous month. I have a filter where I select a certain month, I would like to calculate the rolling total for the previous month.
Below is the calculation that works perfectly to calculate the rolling total for the selected date range.
How can I calculate the previous months rolling total?
Rolling_Total_Current_Month = CALCULATE(
SUM(SalesInvoice[Sales])
,FILTER(ALLSELECTED(SalesInvoice), (SalesInvoice[Date]) <= MAX(SalesInvoice[Date])))
Here is a sample of my data, I have sales per day, for multiple categories, (in fact i have a couple more columns of details but this is simplified)
Date Day Amount Category
1/1/2016 1 100 A
1/1/2016 1 120 B
1/1/2016 1 90 C
1/2/2016 2 500 A
1/2/2016 2 321 B
1/2/2016 2 143 C
So far I have come up with an equation to solve the rolling total, but when I try to slice is and view the rolling total of a single category it does not work for the previous month. I just keeps the original rolling total for the previous month.
Here is the equation for the rolling total previous month that works. But does not recalculate a rolling total for the previous month once sliced based on category.
PREVIOUS_MONTH_ROLLING_TOTAL =
CALCULATE(
[Current Sales]
,FILTER(
ALL( Orders )
,Orders[MonthNumber] = MAX( Orders[MonthNumber] ) - 1
&& Orders[Day] <= MAX( Orders[Day] )
)
)
I have solved how to get the previous months rolling total.
You must do three things. First create a Month Number column in your data sheet (this is used as an integer to subtract 1 month from). You must also create a days column as well.
Then create a measure for Current Sales or whatever your value is.
Create a measure for the current month sales
Current Sales = SUM(Orders[Amount])
Then this equation.
PREVIOUS_MONTH_ROLLING_TOTAL =
CALCULATE(
[Current Sales]
,FILTER(
ALL( Orders )
,Orders[MonthNumber] = MAX( Orders[MonthNumber] ) - 1
&& Orders[Day] <= MAX( Orders[Day] )
)
)
The Idea of this equation is to be able to display the previous months rolling total on a chart with the X axis as "DAY" (so 1-31) Then you can view the current month, previous month, same period last year all on the same chart or table.
Try something along these lines:
Rolling_Total_Previous_Month =
VAR CurrentMonth = MAX(SalesInvoice[Date])
VAR PreviousMonth = EOMONTH(CurrentMonth,-1)
RETURN CALCULATE(SUM(SalesInvoice[Sales]), SalesInvoice[Date] <= PreviousMonth)
To start of, I have a data like this in a table called as Orders-
Date Amount
12/12/2017 100
12/12/2017 200
12/12/2017 300
1/1/2018 400
1/1/2018 500
I first create a calculated column called as Year & Month by using the formula:-
Year = YEAR(Orders[Date])
Month = FORMAT(Orders[Date],"mmmm")
Then I create a column called as Month Number which will be helpful for sorting when more than one year is involved in the table and as well as to Identify the Previous Months.
MonthNumber = DATEDIFF(Min(Orders[Date]),Orders[Date],MONTH)
Current Month Sales can be a measure or a Calculated column. Qn the Question, you had your answer for current month sales via a calculated column and if you want to go for a measure then something like this would work on a summary table.
Current Month Sales = SUm(Orders[Amount])
I would also create a column called as Key:-
Key = Orders[MonthNumber] & Orders[Category]
Now, for the Previous Month Sales, I would create a measure that looks for selected MonthNumber that we created.
Previous Month Sales =
Var SelectedCategory = SELECTEDVALUE(Orders[Category])
Var SelectedMonthNumberr = SELECTEDVALUE(Orders[MonthNumber]) - 1
Var ReqKey = SelectedMonthNumberr & SelectedCategory
Return
IF(ISBLANK(SelectedCategory) <> True(),
CALCULATE(SUM(Orders[Amount]),FILTER(ALL(Orders), Orders[Key] = ReqKey)),
CALCULATE(SUM(Orders[Amount]),FILTER(ALL(Orders), Orders[MonthNumber] = SelectedMonthNumberr)))
or to your Measure
PREVIOUS_MONTH_ROLLING_TOTAL =
CALCULATE(
[Current Sales]
,FILTER(
ALL( Orders )
,Orders[MonthNumber] = MAX( Orders[MonthNumber] ) - 1
&& Orders[Day] <= MAX( Orders[Day] )
)
)
You can just add another filtering item as && Orders[Category] = SELECTEDVALUE(Orders[Category]) but won't work when you don't have any categories selected or on a table or visual which doesn't have categories. So, you would need to define an if else logic here as I have quoted on my measure formula.
Do let me know, if this helps or not.