I am writing a #PostgreSQL query for my company to calculate how many hours a person is OFF working, with a table containing information about requests, with these columns: Request ID, Sender username, Type, Start time, End time.
The sample data for this is:
| Request ID | Sender username | Type | Start time | End time |
|---|---|---|---|---|
| 1 | Smith | OFF | 2023-04-01 8:00:00 | 2023-04-03 13:00:00 |
My company working hours are from 8:30 to 18:00, and lunch break is from 12:00 to 13:30.
I want to write a query that counts how many hours for OFF each day (lunch time not included), and returns this desired result:
| Sender username | Date | Off(hours) |
|---|---|---|
| Smith | 2023-04-01 | 8 |
| Smith | 2023-04-02 | 8 |
| Smith | 2023-04-03 | 3.5 |
Desired result table
For the date 2023-04-01, 8 hours because we only count a number of OFF hours that is in working time from 8:30 to 18:00.
For the date 2023-04-02, 8 hours because All the days between the start time date and end time date is 8 hours.
For the date 2023-04-03, 3.5 hours because since end time (13:00) is in lunch break time, we only count from 8:30 to 12:00
I finish the query for calculating the number of hours for all requests with start time and end time on the same day. For other requests the start time and end time are on different days, so I'm still not able to do them. Please help me.
Something like the following should do what you want:
However, I strongly advise you to have a table listing the company worktimes, instead of a generate_series as I have used in the example. Why? Weekends can be got around, but public holidays would be very difficult to include, not to mention special half-days etc.
By way of explanation, I first select those dates and times where the "off" times coincide with the company worktimes. I then use the greatest and least functions to deal with any overlap - for example if your sample off time had started at 09:00 instead of 08:00, it would have been within the work times, and so we would want to count from 09.00 not 08:30. Having then got the times, it is relatively trivial to extract the hours and partial hours (minutes / 60). All that then remains, is to sum by date and user.