每名员工每天的总工作时间(包括通宵工作时间)

vib*_*ion 3 mysql aggregate sum running-totals

我有一个这样的表:

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       )
+--------------+---------------------+-----------------+
Run Code Online (Sandbox Code Playgroud)

为简洁起见,省略主键 - 请参阅http://www.sqlfiddle.com/#!9/30503/1

0 表示登录 - 1 表示注销。例如,如果员工通宵工作(如员工 5 在 2014-03-02 和 2014-03-03 之间所做的那样),每个用户每天或一段时间内可能会多次登录/注销

我正在尝试获取每个员工每天/轮班的工作总小时数(例如,某些轮班将跨越两天):

1      2014-03-02   total hours worked    08:32:00
Run Code Online (Sandbox Code Playgroud)

我想出了这个查询:

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)
Run Code Online (Sandbox Code Playgroud)

这只给了我最小登录和最大注销之间经过的时间。

从之前的问题中,我了解到如何获取每个员工每天的总工作时间(不包括夜班):

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;
Run Code Online (Sandbox Code Playgroud)

仍然没有找到一种方法来考虑夜班 - 期待您的意见。

周末会有员工上班。假期不再是问题;夏令时也不会。

该应用程序没有适当的检查来防止不同步时钟打孔?例如,打卡/下班记录不按时间顺序或由于员工错误而重复。我已经在我编写的用于连接设备并检索原始数据的代码中解决了此类问题 - 可能更好地处理我的代码中的所有计算。

夜班 100% 从轮班开始之日算起。例如,如果您在 02.01 午夜之前开始工作,则总工作时间将以 02.01 作为日期保存。如果您在午夜之后开始,则总工作时间将以 03.01 作为日期进行保存。

如果没有匹配的注销,我会在为 MySQL 数据库准备原始数据的代码中按照预定义的小时数手动注销用户。

Oll*_*lli 5

请检查性能是否足够:

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;
Run Code Online (Sandbox Code Playgroud)

编辑

每天汇总:

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);
Run Code Online (Sandbox Code Playgroud)