2010-11-04 6 views
14

Tak Mam zestaw wyników, który wygląda mniej więcej tak:MySQL: Jak SUM() a TIMEDIFF() w grupie?

SELECT User_ID, StartTime, EndTime, TIMEDIFF(EndTime, StartTime) AS TimeDiff 
FROM MyTable 

------------------------------------------------------------------ 
| User_ID |  StartTime  |   EndTime  | TimeDiff | 
------------------------------------------------------------------ 
| 1 | 2010-11-05 08:00:00 | 2010-11-05 09:00:00 | 01:00:00 | 
------------------------------------------------------------------ 
| 1 | 2010-11-05 09:00:00 | 2010-11-05 10:00:00 | 01:00:00 | 
------------------------------------------------------------------ 
| 2 | 2010-11-05 06:30:00 | 2010-11-05 07:00:00 | 00:30:00 | 
------------------------------------------------------------------ 
| 2 | 2010-11-05 07:00:00 | 2010-11-05 09:00:00 | 02:00:00 | 
------------------------------------------------------------------ 
| 2 | 2010-11-05 09:00:00 | 2010-11-05 10:00:00 | 01:00:00 | 
------------------------------------------------------------------ 

teraz muszę grupie wyniki według User_ID i SUM() TimeDiff. Jeśli dodaję klauzulę GROUP BY, to nie będzie to SUM() TimeDiff (i nie oczekiwałbym tego). Jak mogę SUM() TimeDiffs dla każdego użytkownika?

Odpowiedz

30

Zastosowanie:

SELECT t.user_id,  
     SEC_TO_TIME(SUM(TIME_TO_SEC(t.endtime) - TIME_TO_SEC(t.starttime))) AS timediff 
    FROM MYTABLE t 
GROUP BY t.user_id 

Kroki:

  1. Stosować TIME_TO_SEC przekonwertować czasu do sekund operacja matematyczna
  2. Suma różnica
  3. Zastosowanie SEC_TO_TIME konwertować sekundy czas powrót do

Na podstawie przykładowych danych, bym właśnie zaproponował:

SELECT t.user_id,  
     TIMEDIFF(MIN(t.startdate), MAX(t.enddate)) AS timediff 
    FROM MYTABLE t 
GROUP BY t.user_id 

UWAGA: Jest błąd w tym kodzie, jeśli korzystasz z datetime. TIME_TO_SEC konwertuje tylko sekcję czasu, więc kończy się dużymi błędami , jeśli zegar minie północ. Użyj UNIX_TIMESTAMP zamiast , aby wykonać sumę. Maksymalnie SEC_TO_TIME przy wartościach większych niż 3020399 sekund, np. SELECT TIME_TO_SEC (SEC_TO_TIME (3020400)); Jeśli masz , zobaczysz tę wartość 838: 59: 59, osiągasz maksimum i prawdopodobnie potrzebujesz , aby podzielić przez 3600, aby pokazać godziny.

+0

Cholera, powinienem wiedzieć wcześniej o 'TIME_TO_SEC', ja i moja kludgy' CONCAT's z losową datą .... +1 dla Ciebie! – Wrikken

+0

@Wrikken: znaczniki czasu epoki nie działały tak dobrze, więc musiałem improwizować :) –

+0

Przepraszam, powinienem być bardziej konkretny. Czasy rozpoczęcia/zakończenia są w rzeczywistości datami. Czy to zmienia twoją odpowiedź? – Andrew

1

Czy to zadziała?

SELECT User_ID, TIME(SUM(TIMEDIFF(EndTime, StartTime))) AS TimeDiff
FROM MyTable GROUP BY User_ID

+1

AFAIK, '' SUM' na wartościach oddać porównywalnych towarów daje przykre rezultaty ('01:30 + 02: 42' staje' 0130 + 0242' => '0372' => niepoprawny czas/NULL – Wrikken

+1

Wrikken jest poprawny - otrzymałem zerowy wynik podczas testowania tego na podstawie przykładowych danych –

+0

+1 Jesteście dobrzy faceci. Zły domysł, próbowałem go i zadziałało prawidłowo, jeśli różnica nie zawiera części minutowych/sekundowych.Tęskniłem za tym, że czas może mieć również minuty/sekundy :( – a1ex07

2

AFAIK, jedyną opcją jest do oddania do UNIX_TIMESTAMP s i zrobić kilka obliczeń na liczbach całkowitych, zastępując losową datę (wybrałem 2000-01-01) dla kolumn czas bez daty.

SELECT TIMEDIFF(
    DATE_ADD('2000-01-01 00:00:00', 
     INTERVAL 
     SUM(UNIX_TIMESTAMP(CONCAT('2000-01-01 ',TimeDiff)) - UNIX_TIMESTAMP('2000-01-01 00:00:00') 
     SECOND), 
    '2000-01-01 00:00:00') 
FROM MyTable; 

Bo to może wydają Można SUM kolumny czas, ale faktycznie zostaną one oddane do nieprzyjemnych liczb całkowitych lub pływaków, które nie pójdą specyfikacji czasowych (spróbuj go z sumą minut> 60 i będziesz zobacz, co mam na myśli).


Dla tych, którzy twierdzą, że można SUM kolumny czasowe:

mysql> create table timetest(a TIME); 
Query OK, 0 rows affected (0.00 sec) 

mysql> INSERT INTO timetest VALUES ('02:00'),('03:00'); 
Query OK, 2 rows affected (0.00 sec) 
Records: 2 Duplicates: 0 Warnings: 0 

mysql> SELECT SUM(a) FROM timetest; 
+--------+ 
| SUM(a) | 
+--------+ 
| 50000 | 
+--------+ 
1 row in set (0.00 sec) 

mysql> SELECT TIME(SUM(a)) FROM timetest; 
+--------------+ 
| TIME(SUM(a)) | 
+--------------+ 
| 05:00:00  | 
+--------------+ 
1 row in set (0.00 sec) 

mysql> -- seems ok, but wait 
mysql> INSERT INTO timetest VALUES ('02:30'); 
Query OK, 1 row affected (0.01 sec) 

mysql> SELECT TIME(SUM(a)) FROM timetest; 
+--------------+ 
| TIME(SUM(a)) | 
+--------------+ 
| 07:30:00  | 
+--------------+ 
1 row in set (0.00 sec) 

mysql> -- and now, oh ye unbelievers: 
mysql> INSERT INTO timetest VALUES ('01:40'); 
Query OK, 1 row affected (0.00 sec) 

mysql> SELECT TIME(SUM(a)) FROM timetest; 
+--------------+ 
| TIME(SUM(a)) | 
+--------------+ 
| NULL   | 
+--------------+ 
1 row in set, 1 warning (0.00 sec) 

mysql> -- why is that? because it uses integer arithmetic, not time - arithmetic: 
mysql> SELECT SUM(a) FROM timetest; 
+--------+ 
| SUM(a) | 
+--------+ 
| 87000 | 
+--------+ 
1 row in set (0.00 sec) 

mysql> -- that cannot be cast to time 
+1

Nie, to nie będzie. Będę edytować w przykładzie, który ma minuty nie liczące "0" w jednym momencie. – Wrikken

+1

Tak, moje złe, I nie zajęło mi wystarczająco dużo czasu, aby zobaczyć, że 1:59 + 1:59 nie jest równe 3:18 :-p. –

+0

Hehe, tutaj, jest w porządku, mógłbyś wierzyć, że mam system płac na tym błędnym założeniu przez kilka tygodni dawno, dawno temu? Wściekłe moby dookoła :) – Wrikken

0

ja proponuję użyć TO_SECONDS zamiast:

SELECT t.user_id,  
     SEC_TO_TIME(SUM(TO_SECONDS(t.endtime) - TO_SECONDS(t.starttime))) AS timediff 
    FROM MYTABLE t 
GROUP BY t.user_id