I’m going to show you how to use the offset function in Power BI. It’s one of the most dynamic tools you can use especially in your date tables.
Once you master how to apply it in your time intelligence projects, you can get more in-depth insights that you won’t get using any other approach. You may watch the full video of this tutorial at the bottom of this blog.
Understanding The Mechanics Of The Offset Function
I’ll start off by showing you the mechanics of the offset function.
Offsets show the difference between today’s date and the other dates in your data.
As you can see in my date table below, I focused on Quarter & Year so that I can see actual data movement.
The purple row shows the current period. Note that the current period always has an offset value of 0.
Above that, in yellow, shows all the data coming from the past. You’ll see that the figures here are either 0 or less than 0, represented by the negative data.
This means that for data from the future, these will show positive values. Depending on the granularity of the column, it may also contain a 0.
So what makes offsets powerful?
Offsets may be sequential numbers representing the difference between different data in the table. But what makes offsets great is that they don’t have boundaries.
For example, quarters will run from 1 to 4, representing the 4 quarters in a year. Months run from 1 to 12 while weeks can run from 1 to 52 or 53, depending on what year it is. But once I reach the last number, I have to start over.
This is not the case for offsets. When it comes to offsets, they will always show a relative position to the current date and the other date being referenced.
So each time the date table is refreshed, the logic that make the offsets work is also updated. This means that an updated value will also be shown in the date table.
Example Of A Week Offset Column
To give you a clearer picture of how the offset function works, I’ll give you an example of how it’s applied.
In my sample data, it shows today’s date as the 24th of April, 2020.
Again, the offset principles state that the current period is represented by 0, future data is represented by positive values and past periods are represented by negative numbers.
I also have a slicer on my page which contains the WeekOffset value. Currently, it shows all values from -53 to 0, with 0 representing the current week.
April 24th (which is today) falls on week 17.
This extended date table only covers the ISO week numbers. This means that weeks start on a Monday. This also means that a week will always contain 7 days.
But there are a lot of custom week requirements that do not follow the same logic. You can find out more about these cases in various topics covered in the Enterprise DNA Forum.
Also, you could consider using Month & Year instead of Week & Year if that better applies to your situation.
Going back to the sample data, you might have noticed that the WeekOffset values are in a perfect sequential number range.
This is because they share the same granularity all throughout. There are no duplicate values and no missing values.
Of course, the Total Sales measure used here is done in the usual way, with just a regular SUMX over Sales for the Quantity times the Price. Then, it all gets aggregated to get a weekly value.
But what if I only want to see the last 4 weeks of sales?
I just have to change my slicer into a range of -3 to 0.
Now, my table only shows those last four weeks of sales.
So as I move through time, my date table gets updated. The same thing happens if new sales results are loaded into the fact table.
Using Offsets In DAX
This time, I’ll show you how the offset function can be used in DAX measures.
I have a table with the Week & Year and Total Sales.
So, if I want to calculate the previous week’s sales without offsets, I would first have to extract what the CurrWeek number is, then check what the CurrYear value is.
If I need to skip past a year boundary, I’ll have to calculate what the MAX Weeknumber is for that last year.
From there, I would use SUMX as an iterating function on the date table. I would also have to check if the CurrWeek is week number 1.
If it’s not week 1, I just need to subtract 1 from the CurrWeek value for the CurrYear. After that, the Total Sales can finally be summed up.
Looking at the table below, you can now see that all the values are perfectly aggregated. The values showing up under Total Sales is simply carried over to the following week.
Even if I move past a year boundary from 2017 to 2018, the pattern doesn’t break. The Total Sales from the last week of 2017 is still perfectly calculated for week number 1 of 2018.
This time, I’m going to do the same calculation, but with date table offsets applied.
This is what that measure looks like when I use offsets.
So to get the PrevWeek value, I just need to reference the selected WeekOffset and subtract 1.
Then, I’ll use the CALCULATE function for Total Sales over ALL Dates where the WeekOffset is equal to the PrevWeek value.
Looking at the results, the results seem to be perfect, even in the transition from 2017 to 2018.
The issue, however, is in the Total. Evidently, this is not the correct value.
Here’s how I’m going to fix that.
First, note that the Week & Year column is in ascending order.
I’m going to change that and sort the column into descending order instead, with 2020 at the top.
Because there is no context coming from the Week & Year, it doesn’t identify the current week’s offset value but is still subtracting 1. But what I can do is apply a cumulative total to adjust the total.
This is what the measure will look like:
The beginning of the measure doesn’t change. It’s exactly the same as the previous measure I applied.
But since I need to use a pattern similar to cumulative totals, I have to use the CALCULATE function on the FirstWeek over the ALLSELECTED Dates with 1 subtracted from it.
I also have to identify the MAX WeekOffset value from the ALLSELECTED dates and subtract one from that as well.
Then, I’ll use the CALCULATE function again for the Total Sales. I’ll use the FILTER function to include ALL Dates. The WeekOffset value should be greater than or equal to the FirstWeek and less than or equal to the LastWeek.
Again, this follows the basic pattern for cumulative totals.
Then I can proceed to checking the grand total by using the IF ISINSCOPE patterns.
So IF the Week & Year ISINSCOPE, I expect the results to show the LWSales. But if it’s not, I expect the LWTotal to show up.
So, if I go back to my table, it will now show the correct Total.
Offsets For Specific Weeks
Let me go back to the example I used earlier where I filtered the data to only show the last four weeks.
If I go into the measure, I can come up with the same results using offsets. This is what that would look like.
I just had to identify the current WeekOffset value for the context coming from the rows.
Once I have that, I can apply the CALCULATE function on the Total Sales of ALL Dates where the WeekOffset is greater than or equal to ThisWeek minus 3, or less than or equal to the value for ThisWeek.
This returns exactly the same value as the example I’m trying to replicate.
***** Related Links *****
Cumulative Totals Based On Monthly Average Results In Power BI
Data Normalization in Power BI for Different Days Results
Build A Comprehensive Date Table In Power BI Really Fast
Conclusion
The examples I showed you above prove how dynamic offsets really are. You can use them in filters, slices, and even in DAX calculations.
Offsets can also be used in extended date tables for weeks, months, quarters, years, and fiscal years. They give a lot of flexibility and can easily help you get the results you want.
Just continue playing around with offsets and see what other uses you can have for them. You can also check the Enterprise DNA Forum for other cases where the offset function proved to be useful.
All the best,
Melissa