web-dev-qa-db-fra.com

Total des heures travaillées par employé par jour, y compris les sessions de nuit

J'ai une table comme ceci:

CREATE TABLE Table1
(ID int, empid int, time datetime, state int);

+--------------+---------------------+-----------------+
|    empid     |       time          |      state      | 
+--------------+---------------------+-----------------+
(      4       | 2014-03-01 11:12:00 |         0       )  
(      5       | 2014-03-01 12:28:06 |         0       )
(      4       | 2014-03-01 12:50:07 |         1       )
(      4       | 2014-03-01 13:38:00 |         0       )
(      5       | 2014-03-01 13:28:06 |         1       )
(      4       | 2014-03-01 18:42:15 |         1       )
(      4       | 2014-03-02 08:11:08 |         0       ) 
(      4       | 2014-03-02 13:26:11 |         1       ) 
(      5       | 2014-03-02 14:16:15 |         0       ) 
(      4       | 2014-03-02 16:16:15 |         0       ) 
(      5       | 2014-03-02 17:48:21 |         1       ) 
(      4       | 2014-03-02 19:39:03 |         1       ) 
(      5       | 2014-03-02 20:16:15 |         0       )
(      5       | 2014-03-03 04:16:15 |         1       )
+--------------+---------------------+-----------------+

touche principale omise pour la brièveté - veuillez vous reporter http://www.sqlfiddle.com/#!9/30503/1

0 signifie connecter - 1 signifie déconnexion. Il peut y avoir plusieurs connexions/déconnages par utilisateur par jour ou par période de jours si, par exemple, un employé travaille la nuit (en tant qu'employé 5 le fait entre 2014-03-02 et 2014-03-03)

J'essaie d'obtenir la somme totale des heures travaillées par employé par jour/décalage (par exemple, certains quarts de travail s'étendront sur deux jours):

1      2014-03-02   total hours worked    08:32:00

Je suis venu avec cette requête:

SELECT CONCAT(
MOD(TIMEDIFF(MAX(CASE WHEN state = '1' THEN time END),
MIN(CASE WHEN state =    '0' THEN time END)), 24 ), ' hours ',
MINUTE(TIMEDIFF(MAX(CASE WHEN state = '1' THEN time END),
MIN(CASE WHEN state    = '0' THEN time END))), ' minutes') as HoursWorked, 
empid, 
Date(time)
FROM emplog T
GROUP BY empid, Date(time)

Ce qui m'a donné seulement le temps écoulé entre la connexion min et max.

D'une autre question J'ai appris à obtenir le total des heures de travail par employé par jour qui n'incluent pas les quarts de nuit:

select empid, work_dt,
    SEC_TO_TIME(sum(TIMESTAMPDIFF(SECOND,login,logout))) as time_worked
from (
select empid, date(time) as work_dt, time as login
    , coalesce(
          (select min(time) 
           from emplog as b 
           where a.empid = b.empid 
             and date(a.time) = date(b.time)
             and b.time >= a.time 
             and b.state = 1
          ), now()) as logout
from emplog as a 
where a.state = 0
) as t
group by empid, work_dt;

N'avez toujours pas compris un moyen de prendre en compte les quarts de nuit - dans l'attente de votre contribution.

Il y aura des employés travaillant pendant le week-end. Les vacances ne seront pas un problème; Ni la lumière du jour, l'heure d'été sera.

L'application n'a pas de chèque en place pour éviter des coups de poing sur des horloges de synchronisation? Par exemple, des enregistrements d'entrée d'horloge hors de la séquence de temps ou dupliqués en raison d'une erreur d'employé. J'ai déjà pris soin de ces types de problèmes dans le code que j'ai écrit pour vous connecter avec l'appareil et récupérer les données brutes - pourrait être préférable de gérer tous les calculs de mon code.

Les quarts de nuit comptent 100% au jour où le changement a commencé. Par exemple, si vous commencez à travailler le 02.01 avant minuit, les heures de travail totales sont enregistrées avec le 02.01 comme date. Si vous commencez après minuit, les heures de travail totales sont enregistrées avec la date de 03,01 à la date.

S'il n'y a pas de déconnexion correspondante, je vous enregistrerai manuellement l'utilisateur avec un nombre prédéfini d'heures dans mon code qui prépare les données brutes de la base de données MySQL.

3
vibration

Veuillez vérifier si la performance suffit:

SELECT empid
      ,SEC_TO_TIME(SUM(TIMESTAMPDIFF(SECOND, time, (SELECT IFNULL(MIN(time),NOW())
                                                      FROM emplog b
                                                     WHERE b.empid = a.empid
                                                       AND b.time  > a.time
                                                       AND b.state = 1
                                                    )))) date_worked
  FROM emplog a
 WHERE state=0
 GROUP BY empid;

éditer

Agréger par jour:

SELECT empid
      ,DATE(time) day
      ,SEC_TO_TIME(SUM(TIMESTAMPDIFF(SECOND, time, (SELECT IFNULL(MIN(time),NOW())
                                                      FROM emplog b
                                                     WHERE b.empid = a.empid
                                                       AND b.time  > a.time
                                                       AND b.state = 1
                                                    )))) date_worked
  FROM emplog a
 WHERE state=0
 GROUP BY empid, DATE(time);
4
Olli