Skip to main content
cancel
Showing results for 
Search instead for 
Did you mean: 

Power BI is turning 10! Let’s celebrate together with dataviz contests, interactive sessions, and giveaways. Register now.

Reply
bigrods
Helper II
Helper II

Calculate Rolling 12 Month Sickness Ratio

Hi All,

I'm trying to create a measure that gives me the rolling 12 month average sickness ratio of employees in our organisation.

I have 3 tables:

SummariseAbsences - all sickness absences recorded with Start Date, End Date, FTE (Ratio of Hours Worked per Day) and Total Days Lost (How many days lost)

Headcount - all staff including Start Date, Termination Date and FTE (Full Time Equivalent - i.e if they work full hours, per week: 1, if they work half hours per week: 0.5)

Calendar  - Date table

 

SummariseAbsences (an Absence End Date of 31/12/4712 means the absence is still open)

AssignmentNoFirst NameSurnameAbsence Start DateAbsence End DateClassificationFTETotal Days Lost
28553628BillBrown06/03/202406/03/2024Short Term11
32409705JohnSmith23/12/202423/12/2024Short Term11
31383209JaneJones04/11/202431/12/4712Long Term0.96112.32
28559843SarahTodd10/09/202431/12/4712Long Term0.5289.44

 

Headcount

AssignmentNoFirst NameSurnameStart DateTermination DateFTE
28553628BillBrown01/04/2020 1
32409705JohnSmith23/06/202215/01/20251
31383209JaneJones01/04/2020 0.96
28559843SarahTodd20/08/2017 0.52
32669532MikeWilson19/08/2024 1
28564640JuliaGibson09/03/202117/10/20241
25226702JamesGreen03/04/202330/05/20241

 

I had created a measure and I can get the % per individual month, but I don't know how to get a rolling average, my measure is as follows:

The _absenttable is to calculate those absences that fall in the last 12 months, but for a rolling 12 month average I'm not sure if something different needs to be done?

The measure also references variable _empfte with an EmpMonth field in the Headcount table - I'd populated the table at the end of each month with a full list of staff members for each month (so employee details were duplicated every month but the EmpMonth column is different) but not sure if I need this for a rolling average and would a single list of employees with Start Date & Termination Date be ok? I'm aware that DATESINPERIOD would need to be used, but not sure how this all goes together, I seem to still be getting the % per month and not a rolling average %.

 

Sickness Absence Ratio % = 

var __startperiod = min('calendar'[Date])
var __endperiod = max('calendar'[Date])
var __empfte =  CALCULATE(SUM('Headcount'[TotalFTE]),FILTER(' Headcount','Headcount'[EmpMonth] = MIN('calendar'[Date])))

 var __absenttable = 
            ADDCOLUMNS(
                FILTER(
                    'SummariseAbsences',
                     ([Absence Start Date] >= __StartPeriod && 
                        [Absence Start Date] < __EndPeriod && [Absence End Date] <= __EndPeriod 
                    ) ||
                        ([Absence Start Date] >= __StartPeriod && 
                            [Absence Start Date] < __EndPeriod && 
                                [Absence End Date] > __EndPeriod
                        ) ||
                            ([Absence Start Date] < __StartPeriod && 
                                [Absence end Date] >= __StartPeriod && 
                                    [Absence End Date] < __EndPeriod
                            ) ||
                                ([Absence Start Date] < __StartPeriod &&
                                    [Absence End Date] > __EndPeriod
                                )
                ),

        
            "__FTESickHours",
            IF (
                'SummariseAbsences'[Absence Start Date] < __startperiod,
                IF (
                    'SummariseAbsences'[Absence End Date] > __endperiod,
                    'SummariseAbsences'[FTE]*(DATEDIFF ( __startperiod, __endperiod, DAY) + 1 ),
                    'SummariseAbsences'[FTE]*(DATEDIFF ( __startperiod, 'SummariseAbsences'[Absence End Date], DAY ) + 1 )
                    ),
                IF (
                    'SummariseAbsences'[Absence End Date] > __endperiod,
                    'SummariseAbsences'[FTE]* ( DATEDIFF ('SummariseAbsences'[Absence Start Date], __endperiod, DAY ) + 1 ),
                    'SummariseAbsences'[FTE]* (DATEDIFF ('SummariseAbsences'[Absence Start Date],'SummariseAbsences'[Absence End Date],DAY) + 1)
                    )
                ) 
            )
       
    var _ftesick = sumx(__absenttable,[__FTESickHours])
    var _absentratio = divide(_ftesick,__empfte,0)
 RETURN
 _absentratio

 Many thanks for any help anyone can give! If anyone needs any more information please let me know - I hope posting this other measure details give some assistance and doesn't confuse matters

1 ACCEPTED SOLUTION

Hi,

 

Thanks so much for the reply - this didn't quite work but I amended the DailyFTE table to check if the MIN and MAX of the calendar table was in the start and end ranges.

 

DailyFTETable = 
ADDCOLUMNS(
    'calendar',
        "EmpFTEAvailable",
            CALCULATE(SUMX('Rolling Sickness Headcount',
                var _start = 'Rolling Sickness Headcount'[Latest Start Date]
                var _end = COALESCE('Rolling Sickness Headcount'[Termination Date],today())
            return
                IF(AND(MIN('calendar'[Date]) >= _start, MAX('calendar'[Date]) <= _end), 'Rolling Sickness Headcount'[FTE],0))),
        "SicknessFTE",
            calculate(SUMX('SummariseAbsences',
                var _absStart = 'SummariseAbsences'[Absence Start Date]
                var _absEnd = IF('SummariseAbsences'[Absence End Date] = date(4712,12,31),today(),'SummariseAbsences'[Absence End Date])
            RETURN
                IF(AND(MIN('calendar'[Date]) >= _absStart, MAX('calendar'[Date]) <= _absEnd),'SummariseAbsences'[FTE],0))
            )
            )

 

RollingSickness = 
    var RollingDates = DATESINPERIOD('calendar'[Date],MAX('calendar'[Date]),-12,month)
    var DailyTable = ADDCOLUMNS(
        FILTER(DailyFTETable, DailyFTETable[Date] in RollingDates),
        "Ratio", DIVIDE([SicknessFTE], [EmpFTEAvailable],0)
    )
    RETURN
    AVERAGEX(DailyTable,[Ratio])

 

I then copied these to make "Short Term" and "Long Term" measures and my visual now works - thanks so much!

 

bigrods_0-1745392271443.png

 

View solution in original post

8 REPLIES 8
v-pbandela-msft
Community Support
Community Support

Hi @bigrods,

I wanted to check if you had the opportunity to review the information provided. Please feel free to contact us if you have any further questions. If my response has addressed your query, please "Accept  as  Solution" and give a 'Kudos' so other members can easily find it.

Thank you,
Pavan.

bhanu_gautam
Super User
Super User

@bigrods , Try using

Sickness Absence Ratio % =
VAR __startperiod = MIN('calendar'[Date])
VAR __endperiod = MAX('calendar'[Date])
VAR __empfte = CALCULATE(
SUM('Headcount'[TotalFTE]),
FILTER('Headcount', 'Headcount'[EmpMonth] = MIN('calendar'[Date]))
)

VAR __absenttable =
ADDCOLUMNS(
FILTER(
'SummariseAbsences',
(
([Absence Start Date] >= __startperiod && [Absence Start Date] < __endperiod && [Absence End Date] <= __endperiod) ||
([Absence Start Date] >= __startperiod && [Absence Start Date] < __endperiod && [Absence End Date] > __endperiod) ||
([Absence Start Date] < __startperiod && [Absence End Date] >= __startperiod && [Absence End Date] < __endperiod) ||
([Absence Start Date] < __startperiod && [Absence End Date] > __endperiod)
)
),
"__FTESickHours",
IF(
'SummariseAbsences'[Absence Start Date] < __startperiod,
IF(
'SummariseAbsences'[Absence End Date] > __endperiod,
'SummariseAbsences'[FTE] * (DATEDIFF(__startperiod, __endperiod, DAY) + 1),
'SummariseAbsences'[FTE] * (DATEDIFF(__startperiod, 'SummariseAbsences'[Absence End Date], DAY) + 1)
),
IF(
'SummariseAbsences'[Absence End Date] > __endperiod,
'SummariseAbsences'[FTE] * (DATEDIFF('SummariseAbsences'[Absence Start Date], __endperiod, DAY) + 1),
'SummariseAbsences'[FTE] * (DATEDIFF('SummariseAbsences'[Absence Start Date], 'SummariseAbsences'[Absence End Date], DAY) + 1)
)
)
)

VAR _ftesick = SUMX(__absenttable, [__FTESickHours])
VAR _absentratio = DIVIDE(_ftesick, __empfte, 0)

VAR Rolling12Months =
CALCULATE(
_absentratio,
DATESINPERIOD('calendar'[Date], MAX('calendar'[Date]), -12, MONTH)
)

RETURN
Rolling12Months




Did I answer your question? Mark my post as a solution! And Kudos are appreciated

Proud to be a Super User!




LinkedIn






Hi @bhanu_gautam 

 

I was getting around 11 - 12% for the rolling 12 month sickness ratio which is not correct, this should be nearer to 6 % as in the chart below:

bigrods_1-1743758052581.png

 

I have amended the measure as I wonder if there needs to be some recognition of employees that join & leave midway through the year? I created a second table called _empftetable but still getting the same figures as above for the rolling average:

 

Rolling Sickness Absence Ratio % = 

var __startperiod = min('calendar'[Date])
var __endperiod = max('calendar'[Date])
 var __absenttable = 
            ADDCOLUMNS(
                FILTER(
                    'SummariseAbsences',
                     ([Absence Start Date] >= __StartPeriod && 
                        [Absence Start Date] < __EndPeriod && [Absence End Date] <= __EndPeriod 
                    ) ||
                        ([Absence Start Date] >= __StartPeriod && 
                            [Absence Start Date] < __EndPeriod && 
                                [Absence End Date] > __EndPeriod
                        ) ||
                            ([Absence Start Date] < __StartPeriod && 
                                [Absence end Date] >= __StartPeriod && 
                                    [Absence End Date] < __EndPeriod
                            ) ||
                                ([Absence Start Date] < __StartPeriod &&
                                    [Absence End Date] > __EndPeriod
                                )
                ),

        
            "__FTESickHours",
            IF (
                'SummariseAbsences'[Absence Start Date] < __startperiod,
                IF (
                    'SummariseAbsences'[Absence End Date] > __endperiod,
                    'SummariseAbsences'[FTE]*(DATEDIFF ( __startperiod, __endperiod, DAY) + 1 ),
                    'SummariseAbsences'[FTE]*(DATEDIFF ( __startperiod, 'SummariseAbsences'[Absence End Date], DAY ) + 1 )
                    ),
                IF (
                    'SummariseAbsences'[Absence End Date] > __endperiod,
                    'SummariseAbsences'[FTE]* ( DATEDIFF ('SummariseAbsences'[Absence Start Date], __endperiod, DAY ) + 1 ),
                    'SummariseAbsences'[FTE]* (DATEDIFF ('SummariseAbsences'[Absence Start Date],'SummariseAbsences'[Absence End Date],DAY) + 1)
                    )
                ) 
            )
var _empftetable = 
    ADDCOLUMNS(
        FILTER(
            'Headcount',
                'Headcount'[Termination Date] = BLANK() || 'Headcount'[Termination Date] > EDATE(max('calendar'[Date]),-12)
        ),
        "_EmpFTEHours",
            'Headcount'[FTE]
    )

    var __empfte = SUMX(_empftetable,[_EmpFTEHours])
    var _ftesick = sumx(__absenttable,[__FTESickHours])
    var _absentratio = divide(_ftesick,__empfte,0)
    var _rolling12months = CALCULATE(_absentratio,DATESINPERIOD('calendar'[Date],MAX('calendar'[Date]),-12,month))
 RETURN
 _rolling12months

Again, many thanks! 

I've been playing around with it more and getting closer but not quite there, I've amended the measure as follows:

 

Rolling Sickness Absence Ratio % = 

var __startperiod = min('calendar'[Date])
var __endperiod = max('calendar'[Date])
 var __absenttable = 
            ADDCOLUMNS(
                FILTER(
                    'SummariseAbsences',
                     ([Absence Start Date] >= __StartPeriod && 
                        [Absence Start Date] < __EndPeriod && [Absence End Date] <= __EndPeriod 
                    ) ||
                        ([Absence Start Date] >= __StartPeriod && 
                            [Absence Start Date] < __EndPeriod && 
                                [Absence End Date] > __EndPeriod
                        ) ||
                            ([Absence Start Date] < __StartPeriod && 
                                [Absence end Date] >= __StartPeriod && 
                                    [Absence End Date] < __EndPeriod
                            ) ||
                                ([Absence Start Date] < __StartPeriod &&
                                    [Absence End Date] > __EndPeriod
                                )
                ),

        
            "__FTESickHours",
            IF (
                'SummariseAbsences'[Absence Start Date] < __startperiod,
                IF (
                    'SummariseAbsences'[Absence End Date] > __endperiod,
                    'SummariseAbsences'[FTE]*(DATEDIFF ( __startperiod, __endperiod, DAY) + 1 ),
                    'SummariseAbsences'[FTE]*(DATEDIFF ( __startperiod, 'SummariseAbsences'[Absence End Date], DAY ) + 1 )
                    ),
                IF (
                    'SummariseAbsences'[Absence End Date] > __endperiod,
                    'SummariseAbsences'[FTE]* ( DATEDIFF ('SummariseAbsences'[Absence Start Date], __endperiod, DAY ) + 1 ),
                    'SummariseAbsences'[FTE]* (DATEDIFF ('SummariseAbsences'[Absence Start Date],'SummariseAbsences'[Absence End Date],DAY) + 1)
                    )
                ) 
            )
var _empftetable = 
    ADDCOLUMNS(
        FILTER(
            'Headcount',
                ('Headcount'[Latest Start Date] < __startperiod && 'Headcount'[Termination Date] > __startperiod) ||
                ('Headcount'[Latest Start Date] < __startperiod && 'Headcount'[Termination Date] = BLANK()) ||
                ('Headcount'[Latest Start Date] >= __startperiod && 'Headcount'[Latest Start Date] <= __endperiod) ||
                ('Headcount'[Latest Start Date] >= __startperiod && 'Headcount'[Latest Start Date] <= __endperiod && 'Headcount'[Termination Date] = blank())
        ),
        "_EmpFTEHours",
            IF(
                'Headcount'[Latest Start Date] < __startperiod,
                IF(('Headcount'[Termination Date] >= __startperiod && 'Headcount'[Termination Date] > __endperiod) || ('Headcount'[Termination Date] = BLANK()),
                        ' Headcount'[FTE]*DATEDIFF(__startperiod,__endperiod,day)+1,
                        IF('Headcount'[Termination Date] >= __startperiod,
                              'Headcount'[FTE]*DATEDIFF(__startperiod,'Headcount'[Termination Date],day)+1)),
                IF('Headcount'[Termination Date] <= __endperiod,
                    'Headcount'[FTE]*DATEDIFF('Headcount'[Latest Start Date],'Headcount'[Termination Date],day)+1,
                    'Headcount'[FTE]*DATEDIFF('Headcount'[Latest Start Date],__endperiod,day)+1
                )
    )
    )
    var __empfte = SUMX(_empftetable,[_EmpFTEHours])
    var _ftesick = sumx(__absenttable,[__FTESickHours])
    var _absentratio = divide(_ftesick,__empfte,0)
    var _rolling12months = CALCULATE(_absentratio,DATESINPERIOD('calendar'[Date],MAX('calendar'[Date]),-12,month))
 RETURN
 _rolling12months

bigrods_0-1743767544903.png

..BUT what I think I actually need is some kind of summary table that summarises both the headcount and the Absences table with a count of each individual day and the sum of FTE and Sickness FTE for that day - then the DATESINPERIOD will work.

So something like this?

DateEmployee FTE AvailableSickness FTE
01-March-202487.658.23
02-March-202487.657.67
03-March-202489.239.25

these fields would need to take into account the Start Date and Termination Date of each employee, and the Start Date and End Date of each absence. I think this is the way to do it?? But I would appreciate any help!

Hi @bigrods,

Thank you for reaching out in Microsoft Community Forum.

Thank you @bhanu_gautam  for the helpful response.

if you're aiming for day-level precision to accurately calculate a rolling 12-month sickness absence ratio, then creating a virtual table that aggregates FTEs and sickness FTEs per day is indeed the most reliable and scalable approach.

Please follow below steps to acheive the error;

1. Create a virtual daily FTE table in a measure using below DAX;

DailyFTETable =
ADDCOLUMNS (
'Calendar',
"EmpFTEAvailable",
CALCULATE (
SUMX (
'Headcount',
VAR Start = 'Headcount'[Start Date]
VAR End = COALESCE('Headcount'[Termination Date], TODAY())
RETURN
IF (
'Calendar'[Date] >= Start && 'Calendar'[Date] <= End,
'Headcount'[FTE],
0
)
)
),
"SicknessFTE",
CALCULATE (
SUMX (
'SummariseAbsences',
VAR AbsStart = 'SummariseAbsences'[Absence Start Date]
VAR AbsEnd = IF('SummariseAbsences'[Absence End Date] = DATE(4712,12,31), TODAY(), 'SummariseAbsences'[Absence End Date])
RETURN
IF (
'Calendar'[Date] >= AbsStart && 'Calendar'[Date] <= AbsEnd,
'SummariseAbsences'[FTE],
0
)
)
)
)

2.Use it to calculate your rolling ratio:

Rolling Sickness Absence Ratio % =
VAR RollingDates =
DATESINPERIOD('Calendar'[Date], MAX('Calendar'[Date]), -12, MONTH)

VAR DailyTable =
ADDCOLUMNS (
FILTER ( DailyFTETable, 'Calendar'[Date] IN RollingDates ),
"Ratio", DIVIDE([SicknessFTE], [EmpFTEAvailable], 0)
)

RETURN
AVERAGEX ( DailyTable, [Ratio] )

Please continue using Microsoft community forum.

If you found this post helpful, please consider marking it as "Accept as Solution" and give it a 'Kudos'. if it was helpful. help other members find it more easily.

Regards,
Pavan.

Hi @v-pbandela-msft 

 

Thanks so much for the reply; I have started to work on your suggestion - I created the first measure but getting an error

"A single value for column 'date' in table 'calendar' cannot be determined"

 

(Apologies - the Headcount table has been renamed 'Rolling Sickness Headcount')

bigrods_0-1744617233057.png

My Calendar table looks as below but there is no actual relationship between this and any other table, should there be?

bigrods_1-1744617325524.png

 

Many thanks for any assistance you could give!

Hi @bigrods,

Thank you for reaching out in Microsoft Community Forum.

please follow below steps for required solution;

1. Create Relationships in your data model
-->'Calendar'[Date] → 'SummariseAbsences'[Absence Start Date]

-->'Calendar'[Date] → 'Headcount'[Start Date] (or equivalent date field)

2.Instead of referencing 'Calendar'[Date] directly, build your daily FTE measure using ADDCOLUMNS + SUMX, like below;

Rolling Daily Table =
VAR _Table =
ADDCOLUMNS (
'Calendar',
"EmpFTEAvailable",
SUMX (
FILTER (
'Headcount',
'Calendar'[Date] >= 'Headcount'[Start Date]
&& (
ISBLANK('Headcount'[Termination Date])
|| 'Calendar'[Date] <= 'Headcount'[Termination Date]
)
),
'Headcount'[FTE]
),
"SicknessFTE",
SUMX (
FILTER (
'SummariseAbsences',
'Calendar'[Date] >= 'SummariseAbsences'[Absence Start Date]
&& (
'Calendar'[Date] <=
IF (
'SummariseAbsences'[Absence End Date] = DATE(4712, 12, 31),
TODAY(),
'SummariseAbsences'[Absence End Date]
)
)
),
'SummariseAbsences'[FTE]
)
)
RETURN
_Table

Please continue using Microsoft community forum.

If you found this post helpful, please consider marking it as "Accept as Solution" and give it a 'Kudos'. if it was helpful. help other members find it more easily.

Regards,
Pavan.

Hi,

 

Thanks so much for the reply - this didn't quite work but I amended the DailyFTE table to check if the MIN and MAX of the calendar table was in the start and end ranges.

 

DailyFTETable = 
ADDCOLUMNS(
    'calendar',
        "EmpFTEAvailable",
            CALCULATE(SUMX('Rolling Sickness Headcount',
                var _start = 'Rolling Sickness Headcount'[Latest Start Date]
                var _end = COALESCE('Rolling Sickness Headcount'[Termination Date],today())
            return
                IF(AND(MIN('calendar'[Date]) >= _start, MAX('calendar'[Date]) <= _end), 'Rolling Sickness Headcount'[FTE],0))),
        "SicknessFTE",
            calculate(SUMX('SummariseAbsences',
                var _absStart = 'SummariseAbsences'[Absence Start Date]
                var _absEnd = IF('SummariseAbsences'[Absence End Date] = date(4712,12,31),today(),'SummariseAbsences'[Absence End Date])
            RETURN
                IF(AND(MIN('calendar'[Date]) >= _absStart, MAX('calendar'[Date]) <= _absEnd),'SummariseAbsences'[FTE],0))
            )
            )

 

RollingSickness = 
    var RollingDates = DATESINPERIOD('calendar'[Date],MAX('calendar'[Date]),-12,month)
    var DailyTable = ADDCOLUMNS(
        FILTER(DailyFTETable, DailyFTETable[Date] in RollingDates),
        "Ratio", DIVIDE([SicknessFTE], [EmpFTEAvailable],0)
    )
    RETURN
    AVERAGEX(DailyTable,[Ratio])

 

I then copied these to make "Short Term" and "Long Term" measures and my visual now works - thanks so much!

 

bigrods_0-1745392271443.png

 

Helpful resources

Announcements
Join our Fabric User Panel

Join our Fabric User Panel

This is your chance to engage directly with the engineering team behind Fabric and Power BI. Share your experiences and shape the future.

June 2025 Power BI Update Carousel

Power BI Monthly Update - June 2025

Check out the June 2025 Power BI update to learn about new features.

June 2025 community update carousel

Fabric Community Update - June 2025

Find out what's new and trending in the Fabric community.