2017-02-22 3 views
1

я могу использовать DATEDIFF, чтобы найти разницу между одним набором дат, как этотРассчитать общее время работало в день с несколькими остановками и начинается

DATEDIFF(MINUTE, @startdate, @enddate) 

, но как бы я найти общий промежуток времени между несколькими наборами даты? Я не знаю, сколько наборов (остановок и запусков) у меня будет.

Данные находятся на нескольких строках с началом и остановкой.

ID  TimeStamp    StartOrStop  TimeCode 
---------------------------------------------------------------- 
1  2017-01-01 07:00:00  Start    1 
2  2017-01-01 08:15:00  Stop    2 
3  2017-01-01 10:00:00  Start    1 
4  2017-01-01 11:00:00  Stop    2 
5  2017-01-01 10:30:00  Start    1 
6  2017-01-01 12:00:00  Stop    2 
+0

'select sum (DATEDIFF (MINUTE, @startdate, @enddate)) ....' –

+1

Является ли это одной строкой с началом/остановкой на запись или началом остановки по двум строкам? Если бы вы могли предоставить образцы данных, это было бы намного проще. –

+0

@JorgeCampos - я бы подумал, что 'select DATEDIFF (MINUTE, min (startdate), max (enddate))' будет более эффективным? – Tony

ответ

1

Этот код будет работать при условии, что ваша таблица только хранить данные от одного человека, и они должны быть порядка Start/Stop/Start/Stop

WITH StartTime AS (
SELECT 
    TimeStamp 
    , ROW_NUMBER() PARTITION BY (ORDER BY TimeStamp) RowNum 
FROM 
    <<table>> 
WHERE 
    TimeCode = 1 
), StopTime AS (
SELECT 
    TimeStamp 
    , ROW_NUMBER() PARTITION BY (ORDER BY TimeStamp) RowNum 
FROM 
    <<table>> 
WHERE 
    TimeCode = 2 
) 
SELECT 
    SUM (DATEDIFF(MINUTE, StartTime.TimeStamp, StopTime.TimeStamp)) As TotalTime 
FROM 
    StartTime 
    JOIN StopTime ON StartTime.RowNum = StopTime.RowNum 
1

Это будет работать, если ваши старты и стопы надежны. Ваш образец имеет два запуска по порядку - начинается 10:00 и 10:30. Я предполагаю, что в процессе производства у вас будет идентификатор сотрудника, и я добавлю его к образцу данных вместо столбца идентификации.

Также на производстве установки CTE будут уменьшены с помощью параметра на дату. Если есть ночные смены, вам нужно, чтобы ваш stops CTE использовал dateadd(day, 1, @startDate) в качестве верхней границы при получении даты окончания.

Настройка образца:

declare @temp table (
    EmpId int, 
    TimeStamp datetime, 
    StartOrStop varchar(55), 
    TimeCode int 
); 

insert into @temp 
values 
(1, '2017-01-01 07:00:00', 'Start', 1), 
(1, '2017-01-01 08:15:00', 'Stop', 2), 
(1, '2017-01-01 10:00:00', 'Start', 1), 
(1, '2017-01-01 11:00:00', 'Stop', 2), 
(2, '2017-01-01 10:30:00', 'Start', 1), 
(2, '2017-01-01 12:00:00', 'Stop', 2) 

Запрос:

;with starts as (
    select t.EmpId, 
      t.TimeStamp as StartTime, 
      row_number() over (partition by t.EmpId order by t.TimeStamp asc) as rn 
    from @temp t 
    where Timecode = 1 --Start time code? 
), 
stops as (
    select t.EmpId, 
      t.TimeStamp as EndTime, 
      row_number() over (partition by t.EmpId order by t.TimeStamp asc) as rn 
    from @temp t 
    where Timecode = 2 --Stop time code? 
) 

select cast(min(sub.StartTime) as date) as WorkDay, 
     sub.EmpId as Employee, 
     min(sub.StartTime) as ClockIn, 
     min(sub.EndTime) as ClockOut, 
     sum(sub.MinutesWorked) as MinutesWorked 
from 
(
    select strt.EmpId, 
      strt.StartTime, 
      stp.EndTime, 
      datediff(minute, strt.StartTime, stp.EndTime) as MinutesWorked 
    from starts strt 
    inner join stops stp 
     on strt.EmpId = stp.EmpId 
     and strt.rn = stp.rn 
)sub 
group by sub.EmpId 
1

Это работает при условии, ваша таблица имеет добавочное ID и перемежения старт/стоп записи

--Data sample as provided 

declare @temp table (
    Id int, 
    TimeStamp datetime, 
    StartOrStop varchar(55), 
    TimeCode int 
); 

insert into @temp 
values 
(1, '2017-01-01 07:00:00', 'Start', 1), 
(2, '2017-01-01 08:15:00', 'Stop', 2), 
(3, '2017-01-01 10:00:00', 'Start', 1), 
(4, '2017-01-01 11:00:00', 'Stop', 2), 
(5, '2017-01-01 10:30:00', 'Start', 1), 
(6, '2017-01-01 12:00:00', 'Stop', 2) 


--let's see every pair start/stop and discard stop/start 

select start.timestamp start, stop.timestamp stop, 
    datediff(mi,start.timestamp,stop.timestamp) minutes 
from @temp start inner join @temp stop 
    on start.id+1= stop.id and start.timecode=1 

--Sum all for required result 

select sum(datediff(mi,start.timestamp,stop.timestamp)) totalMinutes 
from @temp start inner join @temp stop 
    on start.id+1= stop.id and start.timecode=1 

Результаты

+-------------------------+-------------------------+---------+ 
|   start   |   stop   | minutes | 
+-------------------------+-------------------------+---------+ 
| 2017-01-01 07:00:00.000 | 2017-01-01 08:15:00.000 |  75 | 
| 2017-01-01 10:00:00.000 | 2017-01-01 11:00:00.000 |  60 | 
| 2017-01-01 10:30:00.000 | 2017-01-01 12:00:00.000 |  90 | 
+-------------------------+-------------------------+---------+ 

+--------------+ 
| totalMinutes | 
+--------------+ 
|   225 | 
+--------------+ 

Может быть, сложная часть является положение join. Мы должны присоединиться к @table с собой путем отсрочки 1 ID. Вот где on start.id+1= stop.id сделал свою работу.

С другой стороны, для исключения пары остановки/начала мы используем start.timecode=1. В случае, если у нас нет колонки с этой информацией, что-то вроде stop.id%2=0 работает нормально.

+0

@PtotheBZZ вы проверили это решение? дайте мне знать, если вам нужна передовая помощь – Horaciux

 Смежные вопросы

  • Нет связанных вопросов^_^