Как бы рассчитать временные интервалы из списка заездов и выездов? - PullRequest
0 голосов
/ 09 ноября 2008

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

У меня есть таблица, которая содержит Clock Actions, IE "Punch In" и "Punch Out". Он также содержит пользователя, который выполнил это действие, проект, связанный с этим действием, и текущую дату / время.

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

Например, вот пример вывода:

ClockActionID        ActionType DateTime
-------------------- ---------- -----------------------
17                   1          2008-11-08 18:33:56.000
18                   2          2008-11-08 18:33:59.587
19                   1          2008-11-08 18:34:01.023
20                   2          2008-11-08 18:34:02.037
21                   1          2008-11-08 18:45:06.317
22                   2          2008-11-08 18:46:14.597
23                   1          2008-11-08 18:46:16.283
24                   2          2008-11-08 18:46:17.173
25                   1          2008-11-08 18:50:37.830
26                   2          2008-11-08 18:50:39.737
27                   1          2008-11-08 18:50:40.547

(11 row(s) affected)

Где ActionType 1 - это «ClockIn», а ActionType 2 - «ClockOut». Я также сократил столбцы Пользователь, Проект и Описание для краткости.

Мне нужно сгенерировать в чистом SQL набор результатов, например:

Description   |    Total Time

Для каждой пары ClockIn / ClockOut.

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

РЕДАКТИРОВАТЬ: пользователь сможет синхронизировать несколько проектов одновременно, хотя сузив набор результатов до одного проекта, это не должно иметь никакого значения для логики.

Ответы [ 3 ]

1 голос
/ 09 ноября 2008

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

Но это не то, что вы спросили. Это решение вашей проблемы:

DECLARE @clock TABLE (ClockActionID INT PRIMARY KEY IDENTITY, ActionType INT, ActionDateTime DATETIME)

INSERT INTO @clock (ActionType, ActionDateTime) VALUES (1,'20080101 00:00:00')
INSERT INTO @clock (ActionType, ActionDateTime) VALUES (2,'20080101 00:01:00')
INSERT INTO @clock (ActionType, ActionDateTime) VALUES (1,'20080101 00:02:00')
INSERT INTO @clock (ActionType, ActionDateTime) VALUES (2,'20080101 00:03:00')
INSERT INTO @clock (ActionType, ActionDateTime) VALUES (1,'20080101 00:04:00')
INSERT INTO @clock (ActionType, ActionDateTime) VALUES (2,'20080101 00:05:00')
INSERT INTO @clock (ActionType, ActionDateTime) VALUES (1,'20080101 00:06:00')
INSERT INTO @clock (ActionType, ActionDateTime) VALUES (2,'20080101 00:07:00')
INSERT INTO @clock (ActionType, ActionDateTime) VALUES (1,'20080101 00:08:12')
INSERT INTO @clock (ActionType, ActionDateTime) VALUES (2,'20080101 00:09:00')

-- Get the range
SELECT ActionDateTime CheckIn, 
  (SELECT TOP 1 ActionDateTime 
   FROM @clock C2 
   WHERE C2.ActionDateTime > C.ActionDateTime) CheckOut   
FROM @clock C
WHERE ActionType = 1

-- Get the duration
SELECT DATEDIFF(second, ActionDateTime, 
  (SELECT TOP 1 ActionDateTime 
   FROM @clock C2 
   WHERE C2.ActionDateTime > C.ActionDateTime)
  ) / 60.0 Duration_Minutes
FROM @clock C
WHERE ActionType = 1

Обратите внимание, что я использую табличную переменную, которая работает с MS SQL Server только для тестирования. Изменить по мере необходимости. Также обратите внимание, что SQL Server 2000 плохо работает с такими запросами. Вот результаты теста:

CheckIn                 CheckOut
2008-01-01 00:00:00.000 2008-01-01 00:01:00.000
2008-01-01 00:02:00.000 2008-01-01 00:03:00.000
2008-01-01 00:04:00.000 2008-01-01 00:05:00.000
2008-01-01 00:06:00.000 2008-01-01 00:07:00.000
2008-01-01 00:08:12.000 2008-01-01 00:09:00.000

Duration_Minutes
1.000000
1.000000
1.000000
1.000000
0.800000
1 голос
/ 09 ноября 2008

Я думаю, что ваша оригинальная схема хранения имеет недостатки. Вы смотрите на это с точки зрения часов, отсюда ClockAction. Почему не с точки зрения проекта?

TABLE ProjectAction (Projectid, Userid, Type, Start, End)

Тогда простой GROUP BY должен добиться цели.

0 голосов
/ 09 ноября 2008

Думали ли вы о таких вещах, как:

  • кто-то забывает отключить часы, и, таким образом, кажется, что они работали дважды?
  • кто-то забывает включить часы, и, таким образом, кажется, что они работали дважды?

В первом случае правильно ли просто игнорировать второй вход? Принятый ответ свяжет оба входа с одним и тем же временем. Это правильно?

Во втором случае второй тайм-аут будет проигнорирован. Это правильно?

...