Find gaps in timesheet data between certain hours

2019-08-18 22:59发布

问题:

I am trying to find gaps in timesheets between the hours of 8AM and 6PM. I am able to find the gaps for records that are logged, but I cannot figure out how to determine if a record was "missed" - meaning if they started at 8:30 AM, I cannot figure out how to identify the 30 minute gap between 8AM and 8:30 AM (ie. they started work late).

In below example, I can find the two gaps between 12 and 12:30 pm, but not the 8am-8:30am gap and 5:30 to 6pm gap on 5/8, and 8am-8:30am gap on 5/10.

Any ideas to point me in the right direction on how I could approach this?

drop table #time;
create table #time (
    TimesheetId int not null
    , StartTime datetime not null
    , EndTIme datetime not null
);

insert into #time (TimesheetId, StartTime, EndTime)
    values (210, '2017-05-08 05:30:00.000', '2017-05-08 06:30:00.000')
         , (210, '2017-05-08 06:30:00.000', '2017-05-08 08:30:00.000')
         , (210, '2017-05-08 08:30:00.000', '2017-05-08 12:00:00.000')
         , (210, '2017-05-08 12:30:00.000', '2017-05-08 18:30:00.000')
         , (210, '2017-05-09 08:30:00.000', '2017-05-09 12:00:00.000')
         , (210, '2017-05-09 12:30:00.000', '2017-05-09 17:30:00.000')
         , (210, '2017-05-09 22:30:00.000', '2017-05-10 05:30:00.000')
         , (210, '2017-05-10 08:30:00.000', '2017-05-10 18:00:00.000')
;

; with t1 as (
    SELECT TimesheetId
         , StartTime
         , lag(EndTime) OVER (PARTITION BY TimesheetId ORDER BY StartTime) AS prev_endtime
    FROM #time
    where datepart(HH, StartTime) <= 18
        and datepart(HH, EndTime) >= 8
)
select prev_endtime as gapStart
     , StartTime as gapEnd
from t1
where StartTime <> prev_endtime
and cast(prev_endtime as date) = cast(StartTime as date)
;

回答1:

WITH
  a AS(SELECT DATEADD(hh, DATEDIFF(dd, 0, StartTime) * 24 + 8, 0) t,
         TimesheetId FROM #time),
  b AS(SELECT * FROM #time UNION ALL SELECT TimesheetId, t, t FROM a UNION ALL
       SELECT TimesheetId, DATEADD(hh, 10, t), DATEADD(hh, 10, t) FROM a),
  c AS(SELECT TimesheetId,
         LAG(EndTime) OVER (
           PARTITION BY TimesheetId ORDER BY StartTime
         ) prev_fin,
         StartTime
       FROM b),
   d AS(SELECT *, DATEADD(hh, DATEDIFF(dd, 0, prev_fin) * 24 + 8, 0) beg,
          DATEADD(hh, DATEDIFF(dd, 0, prev_fin) * 24 + 18, 0) fin
        FROM c)
SELECT TimesheetId, prev_fin, StartTime
FROM d
WHERE prev_fin < StartTime AND
  ((prev_fin >= beg AND prev_fin < fin) OR
   (StartTime > beg AND StartTime <= fin));

Check it on rextester.com.



回答2:

You can use this to insert a record and then use what you have
Or you could use a UNION

select distinct t1.TimesheetId, dateadd(hh, 8, cast(CONVERT(date, StartTime) as datetime)) as StartTime, dateadd(hh, 8, cast(CONVERT(date, StartTime) as datetime)) as EndTime
  from #time t1  
 where not exists ( select dateadd(hh, 8, cast(CONVERT(date, T2.StartTime) as datetime)), t2.* 
                     from #time T2 
                    where 1 = 1 
                      and t2.TimesheetId = t1.TimesheetId 
                      and CONVERT(date, T2.StartTime) = CONVERT(date, T1.StartTime)
                      and t2.StartTime = dateadd(hh, 8, cast(CONVERT(date, t2.StartTime) as datetime)) 
                  )