Сравнение и перекрытие таймфреймов с тремя различными наборами данных в SQL - PullRequest
0 голосов
/ 29 апреля 2020

Я пытаюсь подвести итог по двум таблицам, но с некоторыми необычными условиями, которые усложняют ситуацию. У меня есть две SQL таблицы - Schedule и PunchClock - каждая из которых имеет три столбца - EmployeeID, StartTime и EndTime (обе в формате datetime).

Мне нужно сравнить эти две таблицы и определить временные рамки всего времени в таблице PunchClock, которые выходят за пределы времени расписания каждого сотрудника.

Например, если XYZ сотрудника был запланирован с «2020-04-28 09:00» на «2020-04» -28 17:00 "в таблице расписания, но они перфорированы в таблицу PunchClock с" 2020-04-28 08:45 "на" 2020-04-28 17:10 ", я должен знать, что их" не запланированное время работы - с «2020-04-28 08:45» до «2020-04-28 09:00», а также с «2020-04-28 17:00» до «2020-04-28 17» : 10" . Мне это нужно было бы независимо от того, как две таблицы перекрывались (или не перекрывались), пока некоторая часть их времени PunchClock падала ВНЕ своего запланированного времени.

Но чтобы бросить в это дополнительный гаечный ключ, я нужно взять это время "незапланированной работы" и найти общую продолжительность времени "незапланированной работы", которая ТОЛЬКО падает между 8: 00-12: 00 или 18: 00-22: 00 в любой день.

Итак, вернемся к моему первоначальному примеру, от времени «незапланированной работы», только «2020-04-28 08:45» до «2020-04-28 09:00» попадают в этот новый состояние. Поэтому общая продолжительность PunchClock времени сотрудника XYZ, когда ОБА выходит за пределы своего времени в расписании И попадает под новые критерии, составит 15 минут (т. Е. С 08:45 до 09:00).

Я пытался построить T- SQL несколькими различными способами, и я продолжаю приближаться, но затем сталкиваюсь с препятствиями. Любая помощь, которую вы можете оказать, будет огромной помощью? Спасибо.

Ответы [ 2 ]

1 голос
/ 30 апреля 2020

вам нужно сравнить временные отрезки и использовать [случай, когда]: я не уверен, хотите ли вы (1) исключить punchClock вне максимума или (2), если вы хотите, чтобы дополнительное время было ограничено максимальным интервалом. здесь (2). если вы хотите (1), просто добавьте предложение where

declare @Schedule   table(EmployeeID int, StartTime datetime, EndTime datetime);
declare @PunchClock table(EmployeeID int, StartTime datetime, EndTime datetime);
insert @Schedule   values(1,'20200428 09:00','20200428 17:00'),(1,'20200429 09:00','20200429 17:00'),(1,'20200430 09:00','20200430 17:00');
insert @PunchClock values(1,'20200428 08:45','20200428 17:10'),(1,'20200429 07:53','20200429 22:03'),(1,'20200330 09:00','20200330 17:00')

declare @Tmin time(0) = '08:00';
declare @Tmax time(0) = '22:00';

select 
     [EmployeeID]   = ISNULL(s.EmployeeID, p.EmployeeID)
    ,[YYYYMMDD]     = ISNULL(CONVERT(CHAR(8), s.StartTime,112), CONVERT(CHAR(8), p.StartTime,112))
    ,[Sched StartTime] = s.StartTime
    ,[Sched EndTime]   = s.EndTime
    ,[Punch StartTime] = p.StartTime
    ,[Punch EndTime]   = p.EndTime

    ,[minutes overClock 1] = case when p.StartTime < s.StartTime then 
                                        DATEDIFF(MINUTE, 
                                                 case when cast(p.StartTime as time(0)) < @Tmin then @Tmin else cast(p.StartTime as time(0)) end,
                                                 cast(s.StartTime as time(0))
                                                ) 
                             end
    ,[minutes overClock 2] = case when p.EndTime > s.EndTime then 
                                        DATEDIFF(MINUTE, 
                                                 cast(s.EndTime as time(0)), 
                                                 case when cast(p.EndTime as time(0)) > @Tmax then @Tmax else cast(p.EndTime as time(0)) end
                                                ) 
                             end

from @Schedule s
FULL OUTER JOIN @PunchClock p on p.EmployeeID = s.EmployeeID /* same empID*/ and /*same day*/ CONVERT(CHAR(8),p.StartTime,112) = CONVERT(CHAR(8),s.StartTime,112)
ORDER BY [EmployeeID],[YYYYMMDD] 

result

0 голосов
/ 30 апреля 2020

Я взял ваши запросы, немного разбил их и расширил. Теперь он охватывает весь сценарий 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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...