2010-11-04 23 views
14

así que tengo un conjunto de resultados que se ve algo como esto:MySQL: Cómo SUM() un TIMEDIFF() en un grupo?

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 | 
------------------------------------------------------------------ 

Ahora necesidad de agrupar los resultados por User_IDSUM() y TIMEDIFF. Si agrego una cláusula GROUP BY, no es SUM() el TimeDiff (y no lo esperaría). ¿Cómo puedo SUM() los TimeDiffs para cada usuario?

Respuesta

30

Uso:

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 

Pasos:

  1. Use TIME_TO_SEC convertir el tiempo a segundos de Operación matemática
  2. suma la diferencia
  3. SEC_TO_TIME uso para convertir los segundos tiempo de volver a

Sobre la base de los datos de la muestra, tendría apenas sugerido:

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

NOTA: No hay un error en este código si está usando datetime. TIME_TO_SEC solo convierte la sección de tiempo para que termine con grandes negativos si el reloj pasa la medianoche. Utilice UNIX_TIMESTAMP en su lugar para hacer la suma. Además, SEC_TO_TIME alcanza un máximo en valores superiores a 3020399 segundos, p. SELECT TIME_TO_SEC (SEC_TO_TIME (3020400)); Si tiene , vea este valor 838: 59: 59 que ha alcanzado el máximo y probablemente solo necesite para dividir por 3600 para mostrar solo las horas.

+0

Maldita sea, debería haber sabido sobre 'TIME_TO_SEC' antes, yo y mi kludgy' CONCAT's con fecha aleatoria .... +1 para ti! – Wrikken

+0

@Wrikken: las marcas de tiempo epoch no funcionaban tan bien, así que tuve que improvisar :) –

+0

lo siento, debería haber sido más específico. Los tiempos de Inicio/Fin son en realidad fechas. ¿Eso cambia tu respuesta? – Andrew

1

¿Funcionará para usted?

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

+1

yo sepa, '' SUM' en valores tiempo' da resultados desagradables ('01:30 + 02: 42' se convierte en' 0130 + 0242' => '0372' => tiempo inválido/NULL. – Wrikken

+1

Wrikken es correcto - Obtuve un resultado nulo como resultado al probar esto en base a los datos de muestra. –

+0

+1. Tienes razón, chicos. Supongo que no, lo intenté y funcionó correctamente si la diferencia no tiene partes minuto/segundo.Me perdí el punto de que el tiempo también puede tener minutos/segundos :( – a1ex07

2

yo sepa, su única opción es echar a UNIX_TIMESTAMP s y hacer algunos cálculos de enteros, la sustitución de una fecha al azar (elegí 2000-01-01) para las columnas tiempo sin una fecha.

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; 

, ya que puede parecer Puede SUM columnas tiempo, pero en realidad serán arrojados a enteros desagradables o flotadores que no seguirán las especificaciones de tiempo (Prueba con una suma de minutos> 60 y se le ver lo que quiero decir).


Para los que dicen que usted puede SUM columnas de la hora:

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

No, no lo hará. Voy a editar en un ejemplo que tiene minutos que no ascienden a '0' en un momento. – Wrikken

+1

Sí, mi mal, yo no tomó suficiente tiempo para ver que 1:59 + 1:59 no es igual a 3:18: -p. –

+0

Hehe, aquí está bien, ¿podría creer que tenía un sistema de nómina ejecutándose en esta suposición incorrecta? durante varias semanas hace mucho tiempo? Mobs enojado por todas partes :) – Wrikken

0

voy a sugerir que utilice TO_SECONDS lugar:

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