Todor
New Member
- Joined
- Oct 14, 2014
- Messages
- 16
- Office Version
- 2019
- Platform
- Windows
Hi there,
I have a fairly complex scenario in Excel that was solved with a LOT of nested formulas. The time attendance is recorded in the biometrics machine which is then exported into a csv or xlsx format. Since the time attendance is checked bi-monthly, there are thousands of logs to be checked. Part of the challenge is that the log is recorded in a single line, which means: employee ID, employee name, date-time, type of log (check-in, check-out, overtime in, overtime out).
If this was done for daytime employees, it would be significantly easier. However, there are night-shift employees checking in after 10 P.M. and checking out the next morning. Here is the short sample of the log record.
There are instances where the employee misses the check-in or check-out or is absent, as well as the public holiday or the weekend. I have solved all scenarios to get times of attendance of to display missed logs with this array formula:
=IFERROR(INDEX(Holiday[Holiday], MATCH(DATEVALUE(Attendance[[#Headers],[12/2/2019]]), Holiday[Date],0)), IFERROR(IF(TIMEVALUE(INDEX(Raw_Data_Nov[Time], MATCH(1, ("Check Out"=Raw_Data_Nov[AttendanceState])*([@[Employee ID]]=Raw_Data_Nov[EmpID])*(DATEVALUE(Attendance[[#Headers],[12/3/2019]])=DATEVALUE(Raw_Data_Nov[Time])), 0)))<0.08, INDEX(Raw_Data_Nov[Date], MATCH(1, ("Check Out"=Raw_Data_Nov[AttendanceState])*([@[Employee ID]]=Raw_Data_Nov[EmpID])*(DATEVALUE(Attendance[[#Headers],[12/3/2019]])=DATEVALUE(Raw_Data_Nov[Time])), 0))*24-INDEX(Raw_Data_Nov[Date], MATCH(1, ("Check In"=Raw_Data_Nov[AttendanceState])*([@[Employee ID]]=Raw_Data_Nov[EmpID])*(DATEVALUE(Attendance[[#Headers],[12/2/2019]])=DATEVALUE(Raw_Data_Nov[Time])), 0))*24, #N/A), IFERROR(IFS(WEEKDAY(Attendance[[#Headers],[12/2/2019]],2)>6, "Sunday", AND(WEEKDAY(Attendance[[#Headers],[12/2/2019]],2)>5, ISERROR(INDEX(Raw_Data_Nov[Date], MATCH(1, ("Check In"=Raw_Data_Nov[AttendanceState])*([@[Employee ID]]=Raw_Data_Nov[EmpID])*(DATEVALUE(Attendance[[#Headers],[12/2/2019]])=DATEVALUE(Raw_Data_Nov[Time])), 0)))), "Saturday", AND(ISERROR(INDEX(Raw_Data_Nov[Date], MATCH(1, ("Check Out"=Raw_Data_Nov[AttendanceState])*([@[Employee ID]]=Raw_Data_Nov[EmpID])*(DATEVALUE(Attendance[[#Headers],[12/2/2019]])=DATEVALUE(Raw_Data_Nov[Time])), 0))), ISERROR(INDEX(Raw_Data_Nov[Date], MATCH(1, ("Check In"=Raw_Data_Nov[AttendanceState])*([@[Employee ID]]=Raw_Data_Nov[EmpID])*(DATEVALUE(Attendance[[#Headers],[12/2/2019]])=DATEVALUE(Raw_Data_Nov[Time])), 0)))), "Absent", ISERROR(INDEX(Raw_Data_Nov[Date], MATCH(1, ("Check In"=Raw_Data_Nov[AttendanceState])*([@[Employee ID]]=Raw_Data_Nov[EmpID])*(DATEVALUE(Attendance[[#Headers],[12/2/2019]])=DATEVALUE(Raw_Data_Nov[Time])), 0))), "No Check In", TIMEVALUE(INDEX(Raw_Data_Nov[Time], MATCH(1, ("Check In"=Raw_Data_Nov[AttendanceState])*([@[Employee ID]]=Raw_Data_Nov[EmpID])*(DATEVALUE(Attendance[[#Headers],[12/2/2019]])=DATEVALUE(Raw_Data_Nov[Time])), 0)))>0.75, INDEX(Raw_Data_Nov[Date], MATCH(1, ("Check Out"=Raw_Data_Nov[AttendanceState])*([@[Employee ID]]=Raw_Data_Nov[EmpID])*(DATEVALUE(Attendance[[#Headers],[12/3/2019]])=DATEVALUE(Raw_Data_Nov[Time])), 0))*24-INDEX(Raw_Data_Nov[Date], MATCH(1, ("Check In"=Raw_Data_Nov[AttendanceState])*([@[Employee ID]]=Raw_Data_Nov[EmpID])*(DATEVALUE(Attendance[[#Headers],[12/2/2019]])=DATEVALUE(Raw_Data_Nov[Time])), 0))*24, AND(ISERROR(INDEX(Raw_Data_Nov[Date], MATCH(1, ("Check Out"=Raw_Data_Nov[AttendanceState])*([@[Employee ID]]=Raw_Data_Nov[EmpID])*(DATEVALUE(Attendance[[#Headers],[12/2/2019]])=DATEVALUE(Raw_Data_Nov[Time])), 0))), ISERROR(INDEX(Raw_Data_Nov[Date], MATCH(1, ("Overtime Out"=Raw_Data_Nov[AttendanceState])*([@[Employee ID]]=Raw_Data_Nov[EmpID])*(DATEVALUE(Attendance[[#Headers],[12/2/2019]])=DATEVALUE(Raw_Data_Nov[Time])), 0)))), "No Check Out"), IFERROR(INDEX(Raw_Data_Nov[Date], SMALL(IF(Raw_Data_Nov[AttendanceState]="Check Out", IF(Raw_Data_Nov[EmpID]=[@[Employee ID]], IF(DATEVALUE(Raw_Data_Nov[Time])=DATEVALUE(Attendance[[#Headers],[12/2/2019]]), ROW(Raw_Data_Nov[Time])-ROW(INDEX(Raw_Data_Nov[Time],1,1))+1))),2))*24-INDEX(Raw_Data_Nov[Date], MATCH(1, ("Check In"=Raw_Data_Nov[AttendanceState])*([@[Employee ID]]=Raw_Data_Nov[EmpID])*(DATEVALUE(Attendance[[#Headers],[12/2/2019]])=DATEVALUE(Raw_Data_Nov[Time])), 0))*24, IFERROR(IF(TIMEVALUE(INDEX(Raw_Data_Nov[Time], MATCH(1, ("Check Out"=Raw_Data_Nov[AttendanceState])*([@[Employee ID]]=Raw_Data_Nov[EmpID])*(DATEVALUE(Attendance[[#Headers],[12/3/2019]])=DATEVALUE(Raw_Data_Nov[Time])), 0)))<0.08, INDEX(Raw_Data_Nov[Date], MATCH(1, ("Overtime Out"=Raw_Data_Nov[AttendanceState])*([@[Employee ID]]=Raw_Data_Nov[EmpID])*(DATEVALUE(Attendance[[#Headers],[12/3/2019]])=DATEVALUE(Raw_Data_Nov[Time])), 0))*24-INDEX(Raw_Data_Nov[Date], MATCH(1, ("Check In"=Raw_Data_Nov[AttendanceState])*([@[Employee ID]]=Raw_Data_Nov[EmpID])*(DATEVALUE(Attendance[[#Headers],[12/2/2019]])=DATEVALUE(Raw_Data_Nov[Time])), 0))*24, INDEX(Raw_Data_Nov[Date], MATCH(1, ("Overtime Out"=Raw_Data_Nov[AttendanceState])*([@[Employee ID]]=Raw_Data_Nov[EmpID])*(DATEVALUE(Attendance[[#Headers],[12/2/2019]])=DATEVALUE(Raw_Data_Nov[Time])), 0))*24-INDEX(Raw_Data_Nov[Date], MATCH(1, ("Check In"=Raw_Data_Nov[AttendanceState])*([@[Employee ID]]=Raw_Data_Nov[EmpID])*(DATEVALUE(Attendance[[#Headers],[12/2/2019]])=DATEVALUE(Raw_Data_Nov[Time])), 0))*24), INDEX(Raw_Data_Nov[Date], MATCH(1, ("Check Out"=Raw_Data_Nov[AttendanceState])*([@[Employee ID]]=Raw_Data_Nov[EmpID])*(DATEVALUE(Attendance[[#Headers],[12/2/2019]])=DATEVALUE(Raw_Data_Nov[Time])), 0))*24-INDEX(Raw_Data_Nov[Date], MATCH(1, ("Check In"=Raw_Data_Nov[AttendanceState])*([@[Employee ID]]=Raw_Data_Nov[EmpID])*(DATEVALUE(Attendance[[#Headers],[12/2/2019]])=DATEVALUE(Raw_Data_Nov[Time])), 0))*24)))))
The data is processed in the dynamic table with dates as headers to give part of the criteria, which is why I had to use the DATEVALUE function.
On thousands of rows of logs and 15 days within the data processing table, with hundreds of employees, formulas take a good amount of time to calculate and recalculate when things change.
I've been using DAX to solve much easier scenarios with much more data, but I can't figure it out for this.
Is there a way to speed things up with DAX for this scenario?
Any help is highly appreciated.
Todor
I have a fairly complex scenario in Excel that was solved with a LOT of nested formulas. The time attendance is recorded in the biometrics machine which is then exported into a csv or xlsx format. Since the time attendance is checked bi-monthly, there are thousands of logs to be checked. Part of the challenge is that the log is recorded in a single line, which means: employee ID, employee name, date-time, type of log (check-in, check-out, overtime in, overtime out).
If this was done for daytime employees, it would be significantly easier. However, there are night-shift employees checking in after 10 P.M. and checking out the next morning. Here is the short sample of the log record.
175 | Pacia.Christien Jake | 12/11/2019 21:59:04 | Check In |
175 | Pacia.Christien Jake | 12/12/2019 08:03:57 | Check Out |
175 | Pacia.Christien Jake | 12/12/2019 21:56:44 | Check In |
175 | Pacia.Christien Jake | 12/13/2019 08:15:32 | Check Out |
175 | Pacia.Christien Jake | 12/16/2019 08:50:58 | Check In |
175 | Pacia.Christien Jake | 12/16/2019 19:43:38 | Check Out |
148 | Palmon.Adnand | 12/02/2019 07:57:16 | Check In |
148 | Palmon.Adnand | 12/02/2019 19:07:20 | Check Out |
148 | Palmon.Adnand | 12/03/2019 07:58:57 | Check In |
148 | Palmon.Adnand | 12/03/2019 18:44:29 | Check Out |
There are instances where the employee misses the check-in or check-out or is absent, as well as the public holiday or the weekend. I have solved all scenarios to get times of attendance of to display missed logs with this array formula:
=IFERROR(INDEX(Holiday[Holiday], MATCH(DATEVALUE(Attendance[[#Headers],[12/2/2019]]), Holiday[Date],0)), IFERROR(IF(TIMEVALUE(INDEX(Raw_Data_Nov[Time], MATCH(1, ("Check Out"=Raw_Data_Nov[AttendanceState])*([@[Employee ID]]=Raw_Data_Nov[EmpID])*(DATEVALUE(Attendance[[#Headers],[12/3/2019]])=DATEVALUE(Raw_Data_Nov[Time])), 0)))<0.08, INDEX(Raw_Data_Nov[Date], MATCH(1, ("Check Out"=Raw_Data_Nov[AttendanceState])*([@[Employee ID]]=Raw_Data_Nov[EmpID])*(DATEVALUE(Attendance[[#Headers],[12/3/2019]])=DATEVALUE(Raw_Data_Nov[Time])), 0))*24-INDEX(Raw_Data_Nov[Date], MATCH(1, ("Check In"=Raw_Data_Nov[AttendanceState])*([@[Employee ID]]=Raw_Data_Nov[EmpID])*(DATEVALUE(Attendance[[#Headers],[12/2/2019]])=DATEVALUE(Raw_Data_Nov[Time])), 0))*24, #N/A), IFERROR(IFS(WEEKDAY(Attendance[[#Headers],[12/2/2019]],2)>6, "Sunday", AND(WEEKDAY(Attendance[[#Headers],[12/2/2019]],2)>5, ISERROR(INDEX(Raw_Data_Nov[Date], MATCH(1, ("Check In"=Raw_Data_Nov[AttendanceState])*([@[Employee ID]]=Raw_Data_Nov[EmpID])*(DATEVALUE(Attendance[[#Headers],[12/2/2019]])=DATEVALUE(Raw_Data_Nov[Time])), 0)))), "Saturday", AND(ISERROR(INDEX(Raw_Data_Nov[Date], MATCH(1, ("Check Out"=Raw_Data_Nov[AttendanceState])*([@[Employee ID]]=Raw_Data_Nov[EmpID])*(DATEVALUE(Attendance[[#Headers],[12/2/2019]])=DATEVALUE(Raw_Data_Nov[Time])), 0))), ISERROR(INDEX(Raw_Data_Nov[Date], MATCH(1, ("Check In"=Raw_Data_Nov[AttendanceState])*([@[Employee ID]]=Raw_Data_Nov[EmpID])*(DATEVALUE(Attendance[[#Headers],[12/2/2019]])=DATEVALUE(Raw_Data_Nov[Time])), 0)))), "Absent", ISERROR(INDEX(Raw_Data_Nov[Date], MATCH(1, ("Check In"=Raw_Data_Nov[AttendanceState])*([@[Employee ID]]=Raw_Data_Nov[EmpID])*(DATEVALUE(Attendance[[#Headers],[12/2/2019]])=DATEVALUE(Raw_Data_Nov[Time])), 0))), "No Check In", TIMEVALUE(INDEX(Raw_Data_Nov[Time], MATCH(1, ("Check In"=Raw_Data_Nov[AttendanceState])*([@[Employee ID]]=Raw_Data_Nov[EmpID])*(DATEVALUE(Attendance[[#Headers],[12/2/2019]])=DATEVALUE(Raw_Data_Nov[Time])), 0)))>0.75, INDEX(Raw_Data_Nov[Date], MATCH(1, ("Check Out"=Raw_Data_Nov[AttendanceState])*([@[Employee ID]]=Raw_Data_Nov[EmpID])*(DATEVALUE(Attendance[[#Headers],[12/3/2019]])=DATEVALUE(Raw_Data_Nov[Time])), 0))*24-INDEX(Raw_Data_Nov[Date], MATCH(1, ("Check In"=Raw_Data_Nov[AttendanceState])*([@[Employee ID]]=Raw_Data_Nov[EmpID])*(DATEVALUE(Attendance[[#Headers],[12/2/2019]])=DATEVALUE(Raw_Data_Nov[Time])), 0))*24, AND(ISERROR(INDEX(Raw_Data_Nov[Date], MATCH(1, ("Check Out"=Raw_Data_Nov[AttendanceState])*([@[Employee ID]]=Raw_Data_Nov[EmpID])*(DATEVALUE(Attendance[[#Headers],[12/2/2019]])=DATEVALUE(Raw_Data_Nov[Time])), 0))), ISERROR(INDEX(Raw_Data_Nov[Date], MATCH(1, ("Overtime Out"=Raw_Data_Nov[AttendanceState])*([@[Employee ID]]=Raw_Data_Nov[EmpID])*(DATEVALUE(Attendance[[#Headers],[12/2/2019]])=DATEVALUE(Raw_Data_Nov[Time])), 0)))), "No Check Out"), IFERROR(INDEX(Raw_Data_Nov[Date], SMALL(IF(Raw_Data_Nov[AttendanceState]="Check Out", IF(Raw_Data_Nov[EmpID]=[@[Employee ID]], IF(DATEVALUE(Raw_Data_Nov[Time])=DATEVALUE(Attendance[[#Headers],[12/2/2019]]), ROW(Raw_Data_Nov[Time])-ROW(INDEX(Raw_Data_Nov[Time],1,1))+1))),2))*24-INDEX(Raw_Data_Nov[Date], MATCH(1, ("Check In"=Raw_Data_Nov[AttendanceState])*([@[Employee ID]]=Raw_Data_Nov[EmpID])*(DATEVALUE(Attendance[[#Headers],[12/2/2019]])=DATEVALUE(Raw_Data_Nov[Time])), 0))*24, IFERROR(IF(TIMEVALUE(INDEX(Raw_Data_Nov[Time], MATCH(1, ("Check Out"=Raw_Data_Nov[AttendanceState])*([@[Employee ID]]=Raw_Data_Nov[EmpID])*(DATEVALUE(Attendance[[#Headers],[12/3/2019]])=DATEVALUE(Raw_Data_Nov[Time])), 0)))<0.08, INDEX(Raw_Data_Nov[Date], MATCH(1, ("Overtime Out"=Raw_Data_Nov[AttendanceState])*([@[Employee ID]]=Raw_Data_Nov[EmpID])*(DATEVALUE(Attendance[[#Headers],[12/3/2019]])=DATEVALUE(Raw_Data_Nov[Time])), 0))*24-INDEX(Raw_Data_Nov[Date], MATCH(1, ("Check In"=Raw_Data_Nov[AttendanceState])*([@[Employee ID]]=Raw_Data_Nov[EmpID])*(DATEVALUE(Attendance[[#Headers],[12/2/2019]])=DATEVALUE(Raw_Data_Nov[Time])), 0))*24, INDEX(Raw_Data_Nov[Date], MATCH(1, ("Overtime Out"=Raw_Data_Nov[AttendanceState])*([@[Employee ID]]=Raw_Data_Nov[EmpID])*(DATEVALUE(Attendance[[#Headers],[12/2/2019]])=DATEVALUE(Raw_Data_Nov[Time])), 0))*24-INDEX(Raw_Data_Nov[Date], MATCH(1, ("Check In"=Raw_Data_Nov[AttendanceState])*([@[Employee ID]]=Raw_Data_Nov[EmpID])*(DATEVALUE(Attendance[[#Headers],[12/2/2019]])=DATEVALUE(Raw_Data_Nov[Time])), 0))*24), INDEX(Raw_Data_Nov[Date], MATCH(1, ("Check Out"=Raw_Data_Nov[AttendanceState])*([@[Employee ID]]=Raw_Data_Nov[EmpID])*(DATEVALUE(Attendance[[#Headers],[12/2/2019]])=DATEVALUE(Raw_Data_Nov[Time])), 0))*24-INDEX(Raw_Data_Nov[Date], MATCH(1, ("Check In"=Raw_Data_Nov[AttendanceState])*([@[Employee ID]]=Raw_Data_Nov[EmpID])*(DATEVALUE(Attendance[[#Headers],[12/2/2019]])=DATEVALUE(Raw_Data_Nov[Time])), 0))*24)))))
The data is processed in the dynamic table with dates as headers to give part of the criteria, which is why I had to use the DATEVALUE function.
On thousands of rows of logs and 15 days within the data processing table, with hundreds of employees, formulas take a good amount of time to calculate and recalculate when things change.
I've been using DAX to solve much easier scenarios with much more data, but I can't figure it out for this.
Is there a way to speed things up with DAX for this scenario?
Any help is highly appreciated.
Todor