[MSSQL] Liczenie czasu pracownika poza pracą

0

Cześć, mam do zrobienia raport, w którego podsumowaniu będzie liczony czas wyjść prywatnych i służbowych pracownika w danym dniu pracy, a także podsumowanie wszystkich.

Całość ma wyglądać jak na przykładzie:
http://img10.imageshack.us/img10/999/examplehra.jpg

Mam taki zbiór danych:

employeeID  |     StartDate   |       name       |      eventDate      |  direction  |  eventType |
---------------------------------------------------------------------------------------------------
   1        |    2009-05-04   |    Jan Kowalski  | 2009-05-04 16:42:19 |  Wyjście    |  Prywatne  |
   1        |    2009-05-04   |    Jan Kowalski  | 2009-05-04 16:41:00 |  Wejście    |  Służbowe  |
   1        |    2009-05-04   |    Jan Kowalski  | 2009-05-04 13:02:21 |  Wyjście    |  Prywatne  |
   1        |    2009-05-04   |    Jan Kowalski  | 2009-05-04 13:00:19 |  Wejście    |  Służbowe  |
   1        |    2009-05-04   |    Jan Kowalski  | 2009-05-04 09:47:05 |  Wyjście    |  Prywatne  |
   1        |    2009-05-04   |    Jan Kowalski  | 2009-05-04 09:23:24 |  Wejście    |  Służbowe  |

I tak dla innych pracowników i innych dni.
Problem stanowi dla mnie policzenie tych czasów spędzonych poza firmą.
Należy pamiętać o tym, że pracownik może nie mieć poprawnej sekwencji(czyli np: "WE - WE - WY" itp).

Mam kilka pomysłów, jak policzyć te podsumowania, ale może ktoś wpadnie na coś prostszego i lepszego.

Pomysł 1. Użycie procedury składowanej i dodatkowej tabeli.
Dodatkowa tabela miałaby kolumny takie jak: employeeID, startDate, out_inDutySum, out_outDutySum

Teraz w procedurze składowanej pobieram te dane do kursora i odejmuję czas wejścia(późniejsze) od wyjścia(wcześniejsze) i tak dla całego dnia pracy. Oczywiście zwracając uwagę na typ wyjścia(prywatne/służbowe).

Następnie, gdy policzę cały dzień, robię insert do tej dodatkowej tabeli.
(alternatywa jest taka, że najpierw robię insert z selecta(distinct) do tej dodatkowej tabeli wszystkich danych, a następnie w procedurze tylko updatuje te dwa pola z sumami. Tylko nie wiem, które lepsze i szybciej się wykona).

Pomysł 2. Sumowanie za pomocą funkcji agregujących
Nie mam zielonego pojęcia, jak to osiągnąć. Wiem, że byłoby najszybsze, ale nie mam pojęcia, jak to zrobić. Dla ułatwienia powiem, że mam dodatkowe dwa pola: isOut, które przyjmuje wartości 0(wejście) lub 1(wyjście) i includeWT, które też przyjmuje takie wartości(0 - prywatne; 1 - służbowe).
Mimo wszystko, nie mam pojęcia, jak się za to zabrać.

Pomysł 3. Sumowanie za pomocą FastReport
Tak chciałem na samym początku, dopóki się nie okazało, że nie ma jak wykombinować. A jeśli nawet się da to zrobić za pomocą FR, to na serwerze policzone na pewno będzie szybciej. Ten pomysł opisałem na forum i grupie dyskusyjnej dot. Fast-Report, ale jak na razie bez odzewu konkretnego :)

Więc jeśli ktoś z Was jest mi w stanie jakoś pomóc, to bardzo proszę :)

0
SELECT employeeID, StartDate, SUM(DATEDIFF(second,dat1,dat2))
FROM
  (SELECT w1.employeeID, w1.StartDate, w1.eventDate dat1, MIN(w2.eventDate) dat2
  FROM wyjscia w1 JOIN wyjscia w2 ON w1.employeeID=w2.employeeID AND w1.StartDate=w2.StartDate AND w1.eventDate<w2.eventDate
  WHERE w1.direction='Wyjście'
  GROUP BY w1.employeeID, w1.StartDate, w1.eventDate) t
GROUP BY employeeID, StartDate
0

Hmmm, nie do końca to liczy to, co chcę. I nie potrafię za bardzo tego rozkminić.
To liczy sumę wszystkich wyjść.

A ja potrzebuję dwie sumy. Sumę wyjść prywatnych i sumę wyjść służbowych.
Wiem, jak zrobić, żebym dostał sumę wyjść prywatnych, lub służbowych. Ale nie idzie mi rozdzielenie tego na dwie kolumny

Może ktoś coś mi jeszcze podrzucić? Bo nie mogę tego rozkminić, a nie chcę za bardzo robić do tego procedury składowanej, skoro można jednym zapytaniem.

[dopisane]

Mój najlepszy pomysł był taki:

SELECT a.employeeID, a.StartDate, SUM(DATEDIFF(ss, a.dat1, a.dat2)) as prywatne,
	SUM(DATEDIFF(ss, b.dat1, b.dat2)) as sluzbowe
FROM
  (SELECT ve.employeeID, ve.StartDate, ve.eventDate as dat1, MIN(ve2.eventDate) as dat2
	FROM dbo.getDetailedEventsReport(11) ve 
	JOIN dbo.getDetailedEventsReport(11) ve2 ON ve.employeeID=ve2.employeeID 
		AND ve.StartDate=ve2.StartDate AND ve.eventDate<ve2.eventDate
  WHERE ve.isOut=1 and ve.includeWT = 0
  GROUP BY ve.employeeID, ve.StartDate, ve.eventDate) a

left join
  (SELECT ve.employeeID, ve.StartDate, ve.eventDate as dat1, MIN(ve2.eventDate) as dat2
	FROM dbo.getDetailedEventsReport(11) ve 
	JOIN dbo.getDetailedEventsReport(11) ve2 ON ve.employeeID=ve2.employeeID 
		AND ve.StartDate=ve2.StartDate AND ve.eventDate<ve2.eventDate
  WHERE ve.isOut=1 and ve.includeWT = 1
  GROUP BY ve.employeeID, ve.StartDate, ve.eventDate) b
	on b.employeeID = a.employeeID and b.StartDate = a.StartDate

GROUP BY a.employeeID, a.StartDate

Tylko, że jakoś źle liczy służbowe wyjścia. Mnoży razy dwa. Tzn. jeśli mam faktycznie 500 sekund służbowych wyjść, to pokaże 1000). Wiem, że mogę sobie podzielić drugą sumę przez 2 i dostanę dobry wynik(przynajmniej z takimi danymi), ale co jeśli w szczególnych przypadkach będzie jeszcze jakoś inaczej liczyło? Czemu on to mnoży?

0
SELECT employeeID, StartDate, 
  SUM(CASE eventType WHEN 'Sluzbowe' THEN DATEDIFF(second,dat1,dat2) ELSE 0 END) sluzbowe,
  SUM(CASE eventType WHEN 'Prywatne' THEN DATEDIFF(second,dat1,dat2) ELSE 0 END) prywatne
FROM
  (SELECT w1.employeeID, w1.StartDate, w1.eventDate dat1, MIN(w2.eventDate) dat2, w1.eventType
  FROM wyjscia w1 JOIN wyjscia w2 ON w1.employeeID=w2.employeeID AND w1.StartDate=w2.StartDate AND w1.eventDate<w2.eventDate
  WHERE w1.direction='Wyjście'
  GROUP BY w1.employeeID, w1.StartDate, w1.eventDate) t
GROUP BY employeeID, StartDate

1 użytkowników online, w tym zalogowanych: 0, gości: 1