Я взял ваши запросы, немного разбил их и расширил. Теперь он охватывает весь сценарий ios, который я искал. Возможно, это не самое элегантное решение, но оно дает мне именно то, что мне нужно. Спасибо, что заставили меня пойти по правильному пути.
declare @Schedule table (EmployeeID int, StartTime datetime, EndTime datetime)
declare @PunchClock table (EmployeeID int, StartTime datetime, EndTime datetime)
declare @BonusShifts table (BonusStartTime TIME(0), BonusEndTime TIME(0))
insert @Schedule
values (1,'2020-04-21 09:00','2020-04-21 17:00'),
(1,'2020-04-22 09:00','2020-04-22 17:00'),
(1,'2020-04-23 09:00','2020-04-23 17:00'),
(1,'2020-04-24 09:00','2020-04-24 17:00'),
(1,'2020-04-25 09:00','2020-04-25 17:00'),
(1,'2020-04-26 09:00','2020-04-26 17:00')
insert @PunchClock
values (1,'2020-04-21 09:45','2020-04-21 14:00'), /* punch fully inside sched */
(1,'2020-04-22 08:30','2020-04-22 17:30'), /* punch fully outsite sched */
(1,'2020-04-23 08:30','2020-04-23 16:30'), /* punch runs before sched with overlap */
(1,'2020-04-24 09:30','2020-04-24 17:30'), /* punch runs after sched with overlap*/
(1,'2020-04-25 07:00','2020-04-25 08:45'), /* punch fully before sched */
(1,'2020-04-26 17:30','2020-04-26 22:00'), /* punch fully after sched */
(1,'2020-04-27 09:00','2020-04-27 12:00') /* punch with no sched */
insert into @BonusShifts
values ('08:00','12:00'),
('18:00','22:00')
declare @WorkTable table (EmployeeID int,
[SchedStartTime] datetime,
[SchedEndTime] datetime,
[PunchStartTime] datetime,
[PunchEndTime] datetime,
[ExtraStart] datetime,
[ExtraEnd] datetime
)
insert into @WorkTable
/** get punches BEFORE scheduled times or punches WITHOUT scheduled times **/
select
p.EmployeeID
,[SchedStartTime] = s.StartTime
,[SchedEndTime] = s.EndTime
,[PunchStartTime] = p.StartTime
,[PunchEndTime] = p.EndTime
,[EarlyExtraStart] = CASE WHEN p.StartTime < s.StartTime OR s.StartTime IS NULL THEN p.StartTime ELSE s.StartTime END
,[EarlyExtraEnd] = CASE WHEN p.StartTime < s.StartTime AND P.EndTime >= S.StartTime THEN s.StartTime
WHEN p.StartTime < s.StartTime AND P.EndTime < S.StartTime THEN p.EndTime
WHEN s.StartTime IS NULL THEN p.EndTime
ELSE s.StartTime END
from @PunchClock p
left join @Schedule s
on p.EmployeeID = s.EmployeeID
and CONVERT(CHAR(8),p.StartTime,112) = CONVERT(CHAR(8),s.StartTime,112)
UNION ALL
/** get punches AFTER scheduled times **/
select
p.EmployeeID
,[SchedStartTime] = s.StartTime
,[SchedEndTime] = s.EndTime
,[PunchStartTime] = p.StartTime
,[PunchEndTime] = p.EndTime
,[LateExtraStart] = CASE WHEN s.StartTime IS NULL THEN NULL
WHEN p.StartTime <= s.EndTime
THEN s.EndTime ELSE p.StartTime END
,[LateExtraEnd] = CASE WHEN s.StartTime IS NULL THEN NULL
WHEN p.EndTime > s.EndTime THEN p.EndTime
ELSE s.EndTime END
from @PunchClock p
left join @Schedule s
on p.EmployeeID = s.EmployeeID
and CONVERT(CHAR(8),p.StartTime,112) = CONVERT(CHAR(8),s.StartTime,112)
/** calculate durations for extra punch times that overlap bonus shift times **/
select *
, [Overlap] = case when ExtraStart<>ExtraEnd AND CAST(ExtraStart AS TIME(0)) <= S.BonusEndTime and CAST(ExtraEnd AS TIME(0)) >= s.BonusStartTime then 'yes' else 'no' end
, [OverlappingMinutes] = case when ExtraStart<>ExtraEnd AND CAST(ExtraStart AS TIME(0)) <= S.BonusEndTime and CAST(ExtraEnd AS TIME(0)) >= s.BonusStartTime then
DATEDIFF(MINUTE,case when CAST(ExtraStart AS TIME(0)) <= BonusStartTime THEN BonusStartTime ELSE CAST(ExtraStart AS TIME(0)) END
,case when CAST(ExtraEnd AS TIME(0)) >= BonusEndTime THEN BonusEndTime ELSE CAST(ExtraEnd AS TIME(0)) END)
ELSE 0 END
from @WorkTable W
cross join @BonusShifts S
ORDER BY EmployeeID,CONVERT(CHAR(8),W.PunchStartTime,112)