2013-05-13 4 views
0

Я пытаюсь написать отчет и немного застрял:/Я пытаюсь показать часы и минуты между двумя датами, но минус нерабочее рабочее время.DATEIFF только в рабочие часы и дни только

Пример рабочего дня рабочих дней с 08:00 до 17:00, и звонок был зарегистрирован в 16:00 сегодня и закрыт завтра в 16:00, так что это будет 24 часа минус рабочие часы, так что это будет работать в 9 ч.

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

Пример данных:

Call_Initiated - Call_Ended 
10/05/2013 15:00 - 13/05/2013 13:00 

Результат Я хотел

Call_Initiated - Call_Ended - Time_To_Resolve 
10/05/2013 15:00 - 13/05/2013 13:00 - 07 

ответ

0

Мне просто интересно о вашей проблеме и сделал это.

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

Это полностью функциональный, но я создал даты, и вы можете использовать свой дневной стол.

declare @callLogStart datetime = '2013-01-04 16:00' 
declare @callLogEnd datetime = '2013-01-08 09:00' 

;with dates(startDate, endDate) 
as 
(
select cast('2013-01-01 08:00' as datetime) 
     ,cast('2013-01-01 17:00' as datetime) 
union all 
select DATEADD(day,1, startDate) 
     ,DATEADD(day, 1, endDate) 
from dates 
where startDate < '2013-02-01 08:00' 
) 
,startDay 
as 
(
    select * 
      ,Datediff(hour, d.startDate, d.endDate) - DATEDIFF(hour, startDate, @callLogStart) as spent 
    from dates d 
    where @callLogStart between d.startDate and d.endDate 
) 
,endDay 
as 
(
    select * 
      ,Datediff(hour, d.startDate, d.endDate) - datediff(hour, @callLogEnd, endDate) as spent 
    from dates d 
    where @callLogEnd between d.startDate and d.endDate 
) 

select --SUM(spent) as actualTime 
     spent 
     ,startDate 
     ,endDate 
     ,mark 
from 
(
    select startDate 
      ,endDate 
      ,spent 
      ,'start' as mark 
    from startDay 
    union 
    select startDate 
      ,endDate 
      ,spent 
      ,'end' 
    from endDay 
    union 
    select s.startDate 
      ,s.endDate 
      ,-Datediff(hour, s.startDate, s.endDate) 
      ,'remove' 
    from startDay s 
    join endDay e 
     on s.startDate = e.startDate 
     and s.endDate = e.endDate 
    union 
    select startDate 
      ,endDate 
      ,Datediff(hour, startDate, endDate) 
      ,'between' 
    from dates 
    where @callLogStart < startDate 
    except 
    select startDate 
      ,endDate 
      ,Datediff(hour, startDate, endDate) 
      ,'between' 
    from dates 
    where @callLogEnd < endDate 
) x 
order by  
    case mark 
     when 'start' then 0 
     when 'between' then 1 
     when 'end' then 2 
     when 'remove' then 3 
    end 

Надеется, что это помогает

+0

Спасибо, Йохан, у меня будет gander :) –

1

Это немного проще. Просто оператор Single select. Я сломал каждый шаг в отдельный столбец, чтобы вы могли видеть, как он работает. Однако вам нужен только последний столбец, чтобы выяснить часы. Он зависит от языкового стандарта, поскольку он использует имена данных, но вы можете перевернуть его в течение дня, пока вы знаете, для чего установлен DATEFIRST.

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

Просто установите дату начала и окончания для того, что вы хотите поиграть с ней, затем, чтобы использовать ее в своем коде, выполните поиск/замену и замените эти параметры своими именами полей. Если вы используете SQL Server 2008 или новее, вы можете упростить его, переключив время открытия/закрытия на типы данных Time. Надеюсь это поможет!

declare @startDate datetime = '2013-09-05 10:45:00.000', 
     @endDate datetime = '2013-09-06 08:15:00.000', 
     @zeroDate datetime = '1900-01-01 00:00:00.000', 
     @businessOpen datetime = '1900-01-01 08:00:00.000', 
     @businessClose datetime = '1900-01-01 17:00:00.000', 
     @hoursOpen int; 

select @hoursOpen = datediff(hour, @businessOpen, @businessClose); 

select @hoursOpen as hoursOpen 
     , @endDate - @startDate as actualTimeCallOpen 
     , datediff(week, @startDate, @endDate) as wholeWeekendsCallOpen 
     , datediff(day, @startDate, @endDate) as daysCallOpen 
     , (DATEDIFF(dd, @StartDate, @EndDate)) --get days apart 
      -(DATEDIFF(wk, @StartDate, @EndDate) * 2) --subtract whole weekends from the date (*2 is for 2 days per weekend) 
       +(CASE WHEN DATENAME(dw, @StartDate) = 'Sunday' THEN 1 ELSE 0 END) --subtract the start date if it started on sunday (thus, partial weekend) 
       -(CASE WHEN DATENAME(dw, @EndDate) = 'Saturday' THEN 1 ELSE 0 END) --subtract the end date if it ends on saturday (again, partial weekend) 
      as MthruFDaysOpen 
     , datediff(hour, @startDate, @endDate) as timeHoursCallOpen 
     , datediff(minute, @businessOpen, convert(datetime, '1900-01-01 ' + convert(varchar(8),@startDate,108)))/60.0 as hoursOpenBeforeCall 
     , datediff(minute, convert(datetime, '1900-01-01 ' + convert(varchar(8), @endDate, 108)), @businessClose)/60.0 as hoursOpenAfterCall 
     , (@hoursOpen - ((datediff(minute, convert(datetime, '1900-01-01 ' + convert(varchar(8), @endDate, 108)), @businessClose) + datediff(minute, @businessOpen, convert(datetime, '1900-01-01 ' + convert(varchar(8),@startDate,108))))/60.0)) as partialHourDay 
     , (((DATEDIFF(dd, @StartDate, @EndDate)) --get days apart, 
      - (DATEDIFF(wk, @StartDate, @EndDate) * 2) --subtract whole weekends from the date 
      + (CASE WHEN DATENAME(dw, @StartDate) = 'Sunday' THEN 1 ELSE 0 END) --subtract the start date if it started on sunday (thus, partial weekend) 
      - (CASE WHEN DATENAME(dw, @EndDate) = 'Saturday' THEN 1 ELSE 0 END) --subtract the end date if it ends on saturday (again, partial weekend) 
      --If you have a table with holidays in it, you can subtract the count of holidays from this as well 
      --test where the holiday is between startdate and end date and the holiday itself isn't a saturday or sunday 
      ) * @hoursOpen) --multiply the whole days open times hours per day, giving us 
     + (@hoursOpen --start with hours open 
      - (-- then subtract the sum of hours the business was open before and after the call 
       (datediff(minute, convert(datetime, '1900-01-01 ' + convert(varchar(8), @endDate, 108)), @businessClose) --calculate this different in minutes for greater accuracy 
        + datediff(minute, @businessOpen, convert(datetime, '1900-01-01 ' + convert(varchar(8),@startDate,108))) 
       )/60.0) --divide by 60 to convert back to hours before subtracting from @hours open 
      ) as businessTimeOpen