2013-06-24 3 views
0

Мне нужно вычислить общее рабочее время из одной таблицы. Моя проблема в том, что рабочее время иногда истекает в конце месяца, и мне нужно рабочее время для каждого месяца. Вот несколько примеров данных:
Рассчитать рабочее время в месяц. MS Access

StartTime EndTime  Staff 
3/31 16:50 3/31 19:30  B 
3/31 23:10 4/1 01:30  B 
4/1 01:40 4/1 03:55  B 

Результат должен быть

Month Staff  WorkingHours 
March  B   3:30 
April  B   1:30 

Заранее спасибо

ответ

1

В этой задаче есть два вида записей

:
  1. запись, в которых [время_запуск] и [конечный момент] находятся в том же месяце, и

  2. запись, в которых они не являются.

Расчет истекшего времени для первого случая легко:

SELECT 
    Staff, 
    Month([StartTime]) AS WorkMonth, 
    DateDiff("n", [StartTime], [EndTime]) AS MinutesWorked 
FROM WorkLog 
WHERE Month([EndTime])=Month([StartTime]) 

Расчета истекшего времени для записей, которые охватывают в месяц границу процесс состоит из двух частей:

(я) Получить истекшее время ранее месяца

SELECT 
    Staff, 
    Month([StartTime]) AS WorkMonth, 
    DateDiff("n", [StartTime], DateSerial(Year([StartTime]), Month([StartTime]) + 1, 1)) AS MinutesWorked 
FROM WorkLog 
WHERE Month([EndTime])>Month([StartTime]) 

(б) Получить истекшее время для followi нг месяца

SELECT 
    Staff, 
    Month([EndTime]) AS WorkMonth, 
    DateDiff("n", DateSerial(Year([EndTime]), Month([EndTime]), 1), [EndTime]) AS MinutesWorked 
FROM WorkLog 
WHERE Month([EndTime])>Month([StartTime]) 

Таким образом, чтобы получить итоговые мы просто UNION ALL три запросы и завернуть их в запросе агрегации для выполнения SUM()

SELECT WorkMonth, Staff, SUM(MinutesWorked) AS TotalMinutes 
FROM 
    (
     SELECT 
      Staff, 
      Month([StartTime]) AS WorkMonth, 
      DateDiff("n", [StartTime], [EndTime]) AS MinutesWorked 
     FROM WorkLog 
     WHERE Month([EndTime])=Month([StartTime]) 
     UNION ALL 
     SELECT 
      Staff, 
      Month([StartTime]) AS WorkMonth, 
      DateDiff("n", [StartTime], DateSerial(Year([StartTime]), Month([StartTime]) + 1, 1)) AS MinutesWorked 
     FROM WorkLog 
     WHERE Month([EndTime])>Month([StartTime]) 
     UNION ALL 
     SELECT 
      Staff, 
      Month([EndTime]) AS WorkMonth, 
      DateDiff("n", DateSerial(Year([EndTime]), Month([EndTime]), 1), [EndTime]) AS MinutesWorked 
     FROM WorkLog 
     WHERE Month([EndTime])>Month([StartTime]) 
    ) 
GROUP BY WorkMonth, Staff 

, который будет возвращать ...

WorkMonth Staff TotalMinutes 
--------- ----- ------------ 
     3 B    210 
     4 B    225 

... и вы можете добавить функции Format(), если вы хотите настроить форматирование месяца (например, как текст) или общее время (например, как «hh: nn»).

+0

+1 Потому что использование SQL всегда предпочтительнее, чем просмотр наборов записей. – Clon

+0

Большое вам спасибо.Это прекрасно решает мою проблему. – user2515536

0

Вы можете посмотреть в логическом выражении с использованием datediff() from here. It позволяет легко вычитать месяцы, дни, часы и т. д.

Если вы должны были добавить в начальной If-Else спрашивать:

If DateDiff("m", #Date1#, #Date2#) = 0 Then 

    'The times here would be in the same month 

Else 

    `The times here would split months 

End If 

И если вы не хотите использовать логический оператор в VBA, вы можете также запустить DateDiff() запрос.

Я не уверен, сколько записей вы имеете в виду здесь, поэтому прохождение каждой записи, если у вас есть 10 с 1000, может быть не самым эффективным, но это выполнит свою работу. Если вы не знакомы с подходом VBA, я был бы рад изменить существующий If-Else с небольшим количеством данных, чтобы указать вам в правильном направлении.

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