Как рассчитать количество дней работы над задачами, если у нас много задач и диапазон дат каждой задачи может перекрываться - PullRequest
0 голосов
/ 11 декабря 2018

Я столкнулся с вопросом во время работы, и я был бы очень признателен, если бы кто-нибудь дал мне несколько идей.

У нас есть таблица, в которой отслеживаются задачи, выполненные сотрудником.Структура таблицы, как показано ниже:

EmployeeNum | TaskID |Start Date of task | End Date of task

Я хочу подсчитать, сколько дней каждый сотрудник вложил в каждую задачу, используя эту таблицу.Сначала мой код выглядит следующим образом:

Select 
   EmployeeNum,TaskID,DateDiff(day,StartDate,EndDate)+1 as PureDay
from
   TaskTable
Group by 
   EmployeeNum,TaskID

Но потом я обнаружил проблему, заключающуюся в том, что для каждой задачи существуют перекрытия в диапазоне дат.

Например, у нас есть TaskA, TaskB, TaskC для одного сотрудника.

  1. Задача A с 2018-10-01 по 2018-10-05
  2. Задача B с 2018-10-02 по 2018-10-07
  3. TaskC изТаким образом, фактические рабочие дни этого сотрудника должны быть с 2018-10-01 по 2018-10-07, а затем с 2018 по 10-10

.10-09 до 2018-10-10, что составляет 9 дней.Если я вычисляю диапазон дат для каждой задачи, а затем складываю их вместе, то фактические рабочие дни становятся 5 + 6 + 2 = 13 дней вместо 9.

Я брожу, если есть какие-либо хорошие способы решить это перекрытиепроблема?Большое спасибо за любые идеи!

Ответы [ 5 ]

0 голосов
/ 12 декабря 2018

Большое спасибо всем за ваш отклик и помощь.Я нашел решение во время поиска в Stackoverflow, вот его ссылка:

Диапазон дат T-SQL в разбиении таблицы и добавление отдельной даты в таблицу

Таблица подсчета, предложенная Феликсом в приведенном выше вопросе, является отличным способом решения моей проблемы, поскольку у меня миллионы записей, а реальная ситуация действительно сложная.

Еще раз всем спасибо за помощь!

0 голосов
/ 11 декабря 2018

Это устраняет перекрывающиеся диапазоны путем корректировки даты начала на основе всех предыдущих дат окончания:

with maxEndDates as
 ( -- find the maximum previous end date
   Select empid,taskid,startdate,enddate,
      max(EndDate)
      over (partition by EmpID 
            order by StartDate, EndDate desc
            rows between unbounded preceding and 1 preceding)  as maxEndDate 
   from TaskTable
 ),
daysPerTask as
 ( -- calculate the difference based on the adjusted start date to eliminate overlaping days
   select *,
      case when maxEndDate >= enddate  then 0                                   -- range already fully covered
           when maxEndDate > startdate then datediff(dd, maxEndDate, enddate)   -- range partially overlapping
           else                             datediff(dd,  startdate, enddate)+1 -- new range 
      end as dayCount 
   from maxEndDates
 )
 -- get the final count
select EmpID, sum(dayCount)
from daysPerTask
group by EmpID;

См. db <> fiddle

0 голосов
/ 11 декабря 2018

Когда вы знаете дату запуска задачи, вы можете использовать накопленную сумму, чтобы назначить группу для каждой записи, а затем просто агрегировать по этой группе (и другой информации).

Следующий запрос должен выполнитьчто вы хотите:

with starts as (
      select sm.*,
             (case when exists (select 1
                                from tb_TaskMaster sm2
                                where sm2.EmpID = sm.EmpID and
                                      sm2.StartDate < sm.StartDate and
                                      sm2.EndDate >= sm.StartDate
                               )
                   then 0 else 1
              end) as isstart
      from tb_TaskMaster sm
     )

select EmpID, count(TaskId) as cnt_TaskID, min(StartDate) as StartDate, max(EndDate) as EndDate,
       datediff(Day, min(StartDate), max(EndDate)) + 1 as PureDay
from (select s.*, sum(isstart) over (partition by EmpID order by StartDate) as grp
      from starts s
     ) s
group by EmpID, grp

order by EmpID

В этом db <> fiddle вы можете найти DDL & DML для данных моего примера и работы кода.

0 голосов
/ 11 декабря 2018

Вы можете попробовать это.

Я не уверен, что это будет работать полностью, но вы можете попробовать его :)

declare @table table (empid int,taskid nvarchar(50),startdate date, enddate date)

insert into @table
values
(1,'TaskA','2018-10-01','2018-10-05'),
(1,'TaskB','2018-10-02','2018-10-07'),
(1,'TaskC','2018-10-09','2018-10-10')


select *,case when comparedate > startdate then datediff(dd,comparedate,enddate) else datediff(dd,startdate,enddate)+1 end  as countofworkingdays from (
Select empid,taskid,startdate,enddate,lag(enddate,1,'1900-01-01') over(partition by empid order by startdate) as CompareDate from @table
)x

Результат

enter image description here

0 голосов
/ 11 декабря 2018

В следующем запросе будет подсчитано, сколько рабочих дней потратил каждый сотрудник на каждую задачу;

SELECT
    EmployeeNum,
    TaskID,
      (DATEDIFF(dd, StartDate, EndDate) + 1)
         -(DATEDIFF(wk, StartDate, EndDate) * 2)
        -(CASE WHEN DATENAME(dw, StartDate) = 'Sunday' THEN 1 ELSE 0 END)
        -(CASE WHEN DATENAME(dw, EndDate) = 'Saturday' THEN 1 ELSE 0 END) as PureDay
FROM
    TaskTable
GROUP BY
    EmployeeNum,
    TaskID

См. эту ссылку , чтобы узнать, как работает этот расчет.

...