Friday, March 14, 2025

Superior Time Intelligence in DAX with Efficiency in Thoughts


Everyone knows the same old Time Intelligence operate based mostly on years, quarters, months, and days. However generally, we have to carry out extra unique timer intelligence calculations. However we should always not neglect to think about efficiency whereas programming the measures. 

Introduction 

There are various Dax capabilities in Energy BI for Time Intelligence Measures. 

The most typical are: 

Yow will discover a complete checklist of Time Intelligence capabilities right here: Time Intelligence – DAX Information. These capabilities cowl the commonest circumstances. 

Nevertheless, some necessities can’t be simply coated with these capabilities. And right here we’re. 

I need to cowl a few of these circumstances I encountered in my initiatives, which embody: 

  • Final n Intervals and a few variants 
  • How to deal with Leap years 
  • Week-to-Date calculations 
  • Calculating Weekly sums 
  • Fiscal Week YTD 

I’ll present you the way to use an prolonged date desk to help these eventualities and enhance effectivity and efficiency. 

Most Time-Intelligence capabilities work no matter whether or not the Fiscal 12 months is aligned with the calendar yr. One exception is 12 months-to-Date (YTD). 

For such circumstances, take a look at the DATESYTD() operate talked about above. There, one can find the non-compulsory parameter to move the final day of the Fiscal yr. 

The final case will cowl calculations based mostly on weeks, whereas the Fiscal yr doesn’t align with the calendar yr. 

Situation 

I’ll use the well-known ContosoRetailDW knowledge mannequin.

The Base Measure is Sum On-line Gross sales, which has the next code: 

Sum On-line Gross sales = SUMX('On-line Gross sales',
 ( 'On-line Gross sales'[UnitPrice]
            * 'On-line Gross sales'[SalesQuantity] ) 
                         - 'On-line Gross sales'[DiscountAmount] )

I’ll work virtually solely in DAX-Studio, which offers the Server Timing operate to investigate the efficiency of the DAX code. Within the References part under, you could find a hyperlink to an article about the way to acquire and interpret efficiency knowledge in DAX Studio. 

That is the bottom question utilized in my examples to get some knowledge from the info mannequin: 

EVALUATE 
 CALCULATETABLE( 
 SUMMARIZECOLUMNS('Date'[Year] 
 ,'Date'[Month Short Name] 
,'Date'[Week] 
,'Date'[Date] 
,"On-line Gross sales", [Sum Online Sales] 
) 
 ,'Product'[ProductCategoryName] = "Computer systems" ,'Product'[ProductSubcategoryName] = "Laptops" 
,'Buyer'[Continent] = "North America" 
 ,'Buyer'[Country] = "United States"  ,'Buyer'[State/Province] = "Texas" )

In most examples, I’ll take away some filters to get extra full knowledge (for every day). 

Date desk 

My date desk features a comparatively massive variety of extra columns. 

Within the references part under, you could find some articles written by SQLBI, on constructing weekly associated calculations, together with making a date desk to help these calculations. 

As described in my article about date tables referenced under, I’ve added the next columns: 

  • Index or Offset columns to rely the times, weeks, months, quarters, semesters, and years from the present date. 
  • Flag columns to mark the present day, week, month, quarter, semester, and yr based mostly on the present date. 
  • This and the earlier columns require a every day recalculation to make sure the proper date is used because the reference date. 
  • Begin- and Finish-Dates of every week and month (Add extra if wanted). 
  • Begin- and Finish-Dates for the Fiscal 12 months. 
  • Earlier yr dates to incorporate the beginning and finish dates of the present interval. That is particularly attention-grabbing for weeks, because the start- and finish dates of the weeks usually are not the identical from yr to yr. 

As you will note, I’ll use these columns extensively to simplify my calculations.

As well as, we’ll use the Calendar Hierarchy to calculate the wanted outcomes at completely different ranges of the hierarchy. 

A whole Calendar hierarchy accommodates both: 

  1. 12 months 
  2. Semester 
  3. Quarter 
  4. Month 
  5. Day 

Or 

  1. 12 months 
  2. Week 
  3. Day 

If the Fiscal 12 months doesn’t align with the Calendar yr, I constructed the Hierarchy with the Fiscal 12 months as a substitute of the Calendar 12 months. 

Then, I added a separate FiscalMonthName column and a FiscalMonthSort column to make sure that the primary month of the fiscal yr was proven first. 

OK, let’s begin with the primary case. 

Final n durations 

This state of affairs calculates the rolling sum of values over the previous n durations. 

For instance, for every day, we need to get the Gross sales for the final 10 days: 

Right here is the Measure I got here up with: 

On-line Gross sales (Final 10 days) = 
 CALCULATE (
 [Sum Online Sales] 
 ,DATESINPERIOD ( 
 'Date'[Date], 
MAX ( 'Date'[Date] ), 
-10, 
DAY 
 ) 
 ) 

When executing the question filtering for Computer systems and North America, I get this end result:

Determine 2 – Final 10 days – Results of Measure (Determine by the Writer)

If I take a look at the server timings, the end result just isn’t dangerous: 

Determine 3 – Server timings for the final 10 days Measure (Determine by the Writer) 

As you may see, the Storage engine performs greater than half of the work, which is an effective signal. It’s not excellent, however because the execution time is lower than 100 ms, it’s nonetheless superb from the efficiency viewpoint. 

This strategy has one essential problem:

When calculating the rolling sum over a number of months, you will need to know that this strategy is date oriented. 

Which means if you take a look at a selected time, it goes again to the identical day of the given month. For instance: 

We take a look at January 12. 2024, and we need to calculate the rolling sum over the past three months. The beginning date for this calculation shall be November 13. 2023. 

When will we need to get the rolling sum for the whole month? 

Within the case above, I need to have because the beginning date November 1, 2023. 

For this case, we will use the MonthIndex column. 

Every column has a novel index based mostly on the present date. 

Due to this fact, we will use it to return three months and get the whole month. 

That is the DAX Code for this: 

On-line Gross sales rolling full 3 months = 
 VAR CurDate = 
 MAX ( 'Date'[Date] ) 
 VAR CurMonthIndex = 
 MAX ( 'Date'[MonthIndex] ) 
 VAR FirstDatePrevMonth = 
 CALCULATE ( 
 MIN ( 'Date'[Date] ), 
 REMOVEFILTERS ( 'Date' ), 
 'Date'[MonthIndex] = CurMonthIndex - 2 
 ) 
 RETURN 
 CALCULATE ( 
 [Sum Online Sales], 
 DATESBETWEEN ( 
 'Date'[Date], 
FirstDatePrevMonth, 
CurDate 
 ) 
 )

The execution continues to be fast, but it surely’s much less environment friendly, as many of the calculations can’t be carried out by the Storage engine:

Determine 4 – Server timings for the rolling sum of the final three full months (Determine by the Writer) As you may see, it isn’t as quick as earlier than. 

I attempted different approaches (for instance, 'Date'[MonthIndex] >= CurMonthIndex – 2 && 'Date'[MonthIndex] <= CurMonthIndex), however these approaches have been worse than this one. 

Right here is the end result for a similar logic, however for the final two months (To keep away from exhibiting too many rows):

Determine 5 – Outcomes for the final two complete months (Determine by the Writer) 

Concerning Leap Years 

The intercalary year downside is odd, which is obvious when calculating the earlier yr for every day. Let me clarify: 

After I execute the next Question to get the final days of February for the years 2020 and 2021: 

EVALUATE 
CALCULATETABLE ( 
 SUMMARIZECOLUMNS ( 
 'Date'[Year], 
 'Date'[Month Short Name], 
 'Date'[MonthKey],
 'Date'[Day Of Month], 
 "On-line Gross sales", [Sum Online Sales], 
 "On-line Gross sales (PY)", [Online Sales (PY)] 
 ), 
 'Date'[Year] IN {2020, 2021}, 
 'Date'[Month] = 2, 
 'Date'[Day Of Month] IN {27, 28, 29}, 
 'Buyer'[Continent] = "North America", 
 'Buyer'[Country] = "United States" 
) 
 ORDER BY 'Date'[MonthKey], 
 'Date'[Day Of Month]

I get the next end result: 

Determine 6 – Drawback of every day PY for the yr after a intercalary year (Determine by the Writer) 

As you may see above, the end result for February 28. 2020 is proven twice, and at some point is lacking the February 2021 for On-line Gross sales (PY). 

When wanting on the month, the sum is right: 

Determine 7 – Appropriate month-to-month sum with leap years (Determine by the Writer) 

The issue is that there is no such thing as a February 29 in 2021. Due to this fact, there is no such thing as a manner that the gross sales for February 29, 2020 shall be displayed when itemizing the Gross sales Quantity per day. 

Whereas the result’s right, it will likely be unsuitable when the info is exported to Excel, and the values are summed. Then, the sum of the every day outcomes will differ from these proven for the whole month. 

This may undermine the customers’ perceived reliability of the info. 

My answer was so as to add a LeapYearDate desk. This desk is a duplicate of the Date desk however and not using a Date column. I added one row annually on February 29, even for non-leap years. 

Then, I added a calculated column for every month and day (MonthDay): 

MonthDay = ('LeapYearDate'[Month] * 100 ) + 'LeapYearDate'[Day Of Month]

The Measure to calculate the earlier yr manually and utilizing the brand new desk is the next:

On-line Gross sales (PY Leap 12 months) = 
 VAR ActYear = 
 SELECTEDVALUE ( 'LeapYearDate'[Year] ) 
 VAR ActDays = 
 VALUES ( 'LeapYearDate'[MonthDay] ) 
 RETURN 
 CALCULATE ( 
 [Sum Online Sales], 
 REMOVEFILTERS ( LeapYearDate ), 
 'LeapYearDate'[Year] = ActYear - 1, 
 ActDays 
 )

As you may see, I acquired the present yr, and through the use of the VALUES() operate, I acquired the checklist of all dates within the present filter context. 

Utilizing this technique, my Measure works for single Days, Months, Quarters, and Years. The results of this Measure is the next: 

Determine 8 – End result for the customized PY Measure, which at all times shows leap days (Determine by the Writer)

As you may see right here, the Measure could be very environment friendly, as many of the work is completed by the Storage engine:

Determine 9 – Server Timings for the customized PY Measure for Leap years (Determine by the Writer) 

However, to be sincere, I don’t like this strategy, though it really works very effectively. 

The reason being that the LeapYearDate desk doesn’t have a date column. Due to this fact, it can’t be used as a Date desk for the present Time Intelligence capabilities. 

We should additionally use the calendar columns from this desk within the visualizations. We can not use the unusual date desk. 

Consequently, we should reinvent all Time Intelligence capabilities to make use of this desk.

I strongly advocate utilizing this strategy solely when crucial. 

Week to Date and PY 

Some Enterprise areas consider Weekly evaluation. 

Sadly, the usual Time Intelligence capabilities don’t help weekly evaluation out of the field. Due to this fact, we should construct our Weekly Measures by ourselves. 

The primary Measure is WTD. 

The primary strategy is the next: 

On-line Gross sales WTD v1 = 
 VAR MaxDate = MAX('Date'[Date]) 
  
 VAR CurWeekday = WEEKDAY(MaxDate, 2) 
  
 RETURN 
 CALCULATE([Sum Online Sales] 
 ,DATESBETWEEN('Date'[Date] 
 ,MaxDate - CurWeekDay + 1  ,MaxDate) 
 )

As you may see, I exploit the WEEKDAY() operate to calculate the beginning date of the week. Then, I exploit the DATESBETWEEN() operate to calculate the WTD. 

If you adapt this sample to your scenario, you will need to be sure that the second parameter in WEEKDAY() is about to the proper worth. Please learn the documentation to study extra about it. 

The result’s the next:

Determine 10 – End result for WTD in DAX Studio (Determine by the Writer) 

One other strategy is to retailer the primary date of every week within the Date desk and use this info within the Measure: 

On-line Gross sales WTD PY v2 = 
 VAR DayOfWeek = MAX('Date'[Day Of Week]) 
  
 VAR FirstDayOfWeek = MIN('Date'[FirstDayOfWeekDatePY])   
 RETURN 
 CALCULATE([Sum Online Sales] 
 ,DATESBETWEEN('Date'[Date] 
 ,FirstDayOfWeek 
,FirstDayOfWeek + DayOfWeek - 1) 
 )

The result’s exactly the identical. 

When analyzing the efficiency in DAX Studio, I see that each Measures are comparable to one another:

Determine 11 – On the left, you may see the execution statistics for the primary model, and on the best, you see them for the second  model. As you may see, each are very comparable (Determine by the Writer)

 

I have a tendency to make use of the second, because it has higher potential when mixed with different Measures. However ultimately, it relies on the present state of affairs. 

One other problem is to calculate the earlier yr. 

Have a look at the next dates for a similar week in numerous weeks: 

Determine 12 – Evaluating the dates of the identical week in numerous years. (Determine by the Writer) 

As you may see, the dates are shifted. And as the usual time intelligence capabilities are based mostly on shifting dates, they won’t work. 

I attempted completely different approaches, however ultimately, I saved the primary date of the identical week for the earlier yr within the date desk and used it like within the second model of WTD proven above: 

On-line Gross sales WTD PY = 
 VAR DayOfWeek = MAX('Date'[Day Of Week]) 
  
 VAR FirstDayOfWeek = MIN('Date'[FirstDayOfWeekDatePY])   
 RETURN 
 CALCULATE([Sum Online Sales] 
 ,DATESBETWEEN('Date'[Date]
 ,FirstDayOfWeek 
,FirstDayOfWeek + DayOfWeek - 1) 
 )

That is the end result: 

Determine 13 – End result for WTD PY Measure (Determine by the Writer) 

Because the logic is similar as within the WTD v2, the efficiency can also be the identical. Due to this fact, this Measure could be very environment friendly. 

Weekly Sums for PY 

Typically, the weekly view is sufficient, and we don’t must calculate the WTD on the Every day degree. 

We don’t want a WTD Measure for this state of affairs for the present yr. The bottom Measure sliced by Week can cowl this. The result’s right out of the field. 

However, once more, it’s one other story for PY.

That is the primary model I got here up with: 

On-line Gross sales (PY Weekly) v1] = 
 VAR ActYear = MAX('Date'[Year]) 
  
 RETURN 
 CALCULATE([Sum Online Sales] 
 ,ALLEXCEPT('Date' 
 ,'Date'[Week] 
) 
 ,'Date'[Year] = ActYear - 1 
 )

Right here, I subtract one from the present yr whereas retaining the filter for the present week. That is the end result:

Determine 14 – The end result for WTD PY for the entire week. See that the WTD end result for the final day of every week corresponds to the PY worth (Determine by the Writer) 

The efficiency is sweet, however I can do higher. 

What if I might retailer a novel Week Identifier within the Date column? 

For instance, the Present Week is 9 of 2025.. 

The Identifier could be 202509. 

After I detract 100 from it, I get 202409, the identifier for a similar week within the earlier yr. After including this column to the date desk, I can change the Measure to this: 

MEASURE 'All Measures'[Online Sales (PY Weekly) v2] = 
VAR WeeksPY = VALUES('Date'[WeekKeyPY]) 
RETURN 
CALCULATE([Sum Online Sales]
,REMOVEFILTERS('Date') 
,'Date'[WeekKey] IN WeeksPY 
)

This model is way less complicated than earlier than, and the end result continues to be the identical. 

After we examine the execution statistics of the 2 variations, we see this: 

Determine 15 – Evaluating the execution statistics of the 2 variations for WTD PY for the entire week. On the left is V1, and on the best is V2. (Determine by the Writer) 

As you may see, the second model, with the precalculated column within the Date desk, is barely extra environment friendly. I’ve solely 4 SE queries, signal for elevated effectivity. 

Fiscal Weeks YTD 

This final one is difficult. 

The requirement is that the consumer needs to see a YTD ranging from the primary day of the primary week of the Fiscal yr. 

For instance, the Fiscal yr begins on July 1. 

In 2022, the week containing July the 1st begins on Monday, June 27. 

Which means the YTD calculation should begin on this date. 

The identical applies to the YTD PY calculation beginning Monday, June 28, 2021. 

This strategy has some penalties when visualizing the info. 

Once more, realizing if the end result have to be proven on the day or week degree is crucial. When exhibiting the info on the day degree, the end result might be complicated when choosing a Fiscal 12 months:

Determine 16 – Results of the weekly based mostly YTD for the Fiscal yr 22/23 (Determine by the Writer) 

As you may see, Friday is the primary day of the Fiscal yr. And the YTD end result doesn’t begin on July 1st however on Monday of that week. 

The consequence is that the YTD doesn’t appear to start out accurately. The customers should know what they’re . 

The identical is legitimate for the YTD PY outcomes. 

To facilitate the calculations, I added extra columns to the Date desk: 

  • FiscalYearWeekYear—This area accommodates the numerical illustration of the Fiscal yr (for 23/24, I get 2324), beginning with the primary week of the Fiscal yr. 
  • FiscalYearWeekYearPY – The identical as earlier than, however for the earlier yr (FiscalYearWeekYear – 101). 
  • FiscalWeekSort—This sorting column begins the week with the primary day of the fiscal yr. A extra elaborate manner to make use of this column could possibly be to observe the ISO-Week definition, which I didn’t do to maintain it easier. 
  • FiscalYearWeekSort – The identical as earlier than however with the FiscalYearWeekYear in entrance (e. g. 232402). 
  • FirstDayOfWeekDate – The date of the Monday of the week through which the present date is in.

Right here is the Measure for the Every day YTD:

On-line Gross sales (Fiscal Week YTD) =
VAR FiscalYearWeekYear = MAX('Date'[FiscalYearWeekYear])
VAR StartFiscalYear = CALCULATE(MIN('Date'[Date])
,REMOVEFILTERS('Date')
,'Date'[FiscalYearWeekSort] =

FiscalYearWeekYear * 100 + 1

)

VAR FiscalYearStartWeekDate = CALCULATE(MIN('Date'[FirstDayOfWeekDate])
,ALLEXCEPT('Date'
,'Date'[FiscalYearWeekYear]
)
,'Date'[Date] = StartFiscalYear

)
VAR MaxDate = MAX('Date'[Date])
RETURN
CALCULATE([Sum Online Sales]
,REMOVEFILTERS('Date')

,DATESBETWEEN('Date'[Date]
,FiscalYearStartWeekDate

,MaxDate
)

Right here is the DAX Code for the Every day YTD PY:

On-line Gross sales (Fiscal Week YTD) (PY)] =
VAR FiscalYearWeekYear = MAX('Date'[FiscalYearWeekYear])
-- Get the Week/Weekday firstly of the present Fiscal 12 months
VAR FiscalYearStart = CALCULATE(MIN('Date'[Date])
,REMOVEFILTERS('Date')
,'Date'[FiscalYearWeekSort] =

FiscalYearWeekYear * 100 + 1
)
VAR MaxDate = MAX('Date'[Date])
-- Get the variety of Days because the begin of the FiscalYear
VAR DaysFromFiscalYearStart =
DATEDIFF( FiscalYearStart, MaxDate, DAY )
-- Get the PY Date of the Fiscal 12 months Week Begin date
VAR DateWeekStartPY = CALCULATE(MIN('Date'[Date])
,REMOVEFILTERS('Date')
,'Date'[FiscalYearWeekSort] =

(FiscalYearWeekYear - 101) * 100 + 1
)
RETURN
CALCULATE(
[Sum Online Sales],
DATESBETWEEN(
'Date'[Date],
DateWeekStartPY,
DateWeekStartPY + DaysFromFiscalYearStart

)
)

As you may see, each Measures observe the identical sample: 

  1. Get the present Fiscal 12 months. 
  2. Get the Beginning Date of the present Fiscal 12 months. 
  3. Get the Beginning date of the week beginning the Fiscal 12 months. 
  4. Calculate the End result based mostly on the Distinction between these two dates 

For the PY Measure, one extra step is required: 

  • Calculate the times between the beginning and present dates to calculate the proper YTD. That is crucial due to the date shift between the years. 

And right here is the DAX code for the weekly base YTD: 

On-line Gross sales (Fiscal Week YTD) =
VAR FiscalWeekSort = MAX( 'Date'[FiscalWeekSort] )
-- Get the Week/Weekday firstly of the present Fiscal 12 months
VAR FiscalYearNumber = MAX( 'Date'[FiscalYearWeekYear] )

RETURN
CALCULATE(
[Sum Online Sales],
REMOVEFILTERS('Date'),
'Date'[FiscalYearWeekSort] >= (FiscalYearNumber * 100 ) + 1
&& 'Date'[FiscalYearWeekSort] <= (FiscalYearNumber * 100 ) +
FiscalWeekSort
)

For the weekly YTD PY, the DAX code is the next: 

On-line Gross sales (Fiscal Week YTD) (PY) =
VAR FiscalWeekSort = MAX( 'Date'[FiscalWeekSort] )
-- Get the Week/Weekday firstly of the present Fiscal 12 months
VAR FiscalYearNumberPY = MAX( 'Date'[FiscalYearWeekYearPY] )
RETURN
CALCULATE(
[Sum Online Sales],
REMOVEFILTERS('Date'),
'Date'[FiscalYearWeekSort] >= (FiscalYearNumberPY * 100) + 1
&& 'Date'[FiscalYearWeekSort] <= (FiscalYearNumberPY * 100) +
FiscalWeekSort
)

Once more, each Measures observe the identical sample: 

  1. Get the present (Type-) variety of the week within the Fiscal yr.
  2. Get the beginning date for the fiscal yr’s first week.
  3. Calculate the end result based mostly on these values.

The end result for the weekly based mostly Measure is the next (On the weekly degree, as the worth is the identical for every day of the identical week): 

Determine 17 – End result for the primary three weeks per Fiscal 12 months with the weekly based mostly YTD and PY Measure (Determine by the Writer) 

When evaluating the 2 Approaches, the Measure for the weekly calculation is extra environment friendly than the one for the every day calculation:

Determine 18 – Evaluating the execution statistics for the 2 Measures. On the left is the every day, and on the best is the weekly calculation. They’re the identical for the calculation for the present and the earlier yr (Determine by the Writer) 

As you may see, the Measure for the weekly result’s sooner, has a extra good portion executed within the Storage Engine (SE), and has fewer SE queries. 

Due to this fact, it may be a good suggestion to ask the customers in the event that they want a WTD end result on the day degree or if it’s sufficient to see the outcomes on the week degree. 

Conclusion 

If you begin writing Time Intelligence expressions, contemplate whether or not extra calculated columns in your date desk might be useful. 

A fastidiously crafted and prolonged date desk might be useful for 2 causes: 

  • Make Measures simpler to write down 
  • Enhance the efficiency of the Measures 

They are going to be simpler to write down as I don’t must carry out the calculations to get the middleman outcomes to calculate the required outcomes. 

The consequence of shorter and less complicated Measures is healthier effectivity and efficiency. 

I’ll add increasingly columns to the template of my date desk as I encounter extra conditions through which they are often useful. 

One query stays: Learn how to construct it? 

In my case, I used an Azure SQL database to create the desk utilized in my examples. 

However it’s doable to create a date desk as a DAX desk or use Python or JavaScript in Cloth or no matter knowledge platform you utilize. 

An alternative choice is to make use of the Bravo device from SQLBI, which lets you create a DAX desk containing extra columns to help unique Time Intelligence eventualities. 

References 

Yow will discover extra details about my date-table right here

Learn this piece to discover ways to extract efficiency knowledge in DAX-Studio and the way to interpret it. 

An SQLBI article about constructing a date desk to help weekly calculations: Utilizing weekly calendars in Energy Bi – SQLBI 

SQLBI Sample to carry out additional weekly calculations: 

Week-related calculations – DAX Patterns 

Like in my earlier articles, I exploit the Contoso pattern dataset. You’ll be able to obtain the ContosoRetailDW Dataset at no cost from Microsoft right here

The Contoso Knowledge might be freely used underneath the MIT License, as described right here.

I modified the dataset to shift the info to modern dates. 


Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles

PHP Code Snippets Powered By : XYZScripts.com