计算日期范围之间每个工作日的工作时间

时间:2014-10-07 21:53:48

标签: mysql sql date datetime

我有一个表格时间表和以下字段

TAId int(11) NOT NULL AUTO_INCREMENT, PostId int(11) NOT NULL, PositionId int(11) NOT NULL, CreatedBy int(11) NOT NULL, ModifiedBy int(11) NOT NULL, CreatedDate datetime NOT NULL, ModifiedDate datetime NOT NULL, TimeIn datetime NOT NULL, TimeOut datetime DEFAULT NULL, TimeBilled tinyint(1) NOT NULL DEFAULT '0', DeviceId varchar(50) DEFAULT NULL, UserId int(11) DEFAULT NULL, oldid varchar(45) DEFAULT NULL, FromCallIn tinyint(1) DEFAULT '0'

我需要按照日期范围之间的周结束日期对每个用户的每个工作时间进行分组。那是我给了一个日期范围。首先,我需要知道timein将介于此日期范围之间,然后我需要获得所有周结束日期,然后每周我需要计算每天的工作时间。

另外,在计算工作时间时,我需要检查timein和timeout之间的差异是否超过一天,然后这些工作时间将分开两天而不是一天。

我知道这有点复杂,如果需要更多解释,请告诉我。

1 个答案:

答案 0 :(得分:1)

以下是一种可能方法的示例/演示:

SELECT r.dt + INTERVAL 7-DAYOFWEEK(r.dt) DAY AS week_ending
     , t.userid
     , r.dt
     , SUM(TIMESTAMPDIFF(SECOND
             ,GREATEST(r.dt,t.timein)
             ,LEAST(r.dt+INTERVAL 1 DAY,t.timeout)
           )
       )/3600 AS hours_worked
  FROM ( SELECT '2014-09-28' AS rb, '2014-10-11' AS re) dr
  JOIN ( SELECT DATE(i.timein) AS dt FROM mytable i 
          UNION
         SELECT DATE(o.timeout) FROM mytable o
       ) r
    ON r.dt BETWEEN DATE(dr.rb) AND DATE(dr.re)
  JOIN mytable t
    ON t.timein  < r.dt+INTERVAL 1 DAY
   AND t.timeout > r.dt
 GROUP BY t.userid, r.dt
 ORDER BY week_ending, t.userid, r.dt

注意:week_ending会返回工作日期之后的星期六的日期。

日期范围在内联视图dr(日期范围)中指定,范围开始日期为列rb,范围结束日期为列re。这个例子显示了两个星期的范围,从2014-09-28周日开始,整整两周,包括2014-10-11周六的工作时间。 (re的值可以从rb得到整数天,得到14整天,`rb + INTERVAL 13 DAY)

仅报告在这些日期或这些日期之间的天数工作的小时数。给定的用户ID没有任何工作&#34; time&#34;在给定日期,该日期不会返回一行。 (可以轻松调整查询以返回范围内所有日期的所有员工的行,并返回零。)

缺席&#34; cal&#34;包含所有日期值的日历表,我们可以从表本身获得一个明确的日期值列表;对于表中的大量或行,这可能是相对昂贵的操作。这不会返回不会出现在timein或timeout列中的日期值。 (如果有超过24小时的工作时间,例如从周一开始到周三结束。并且周三没有其他行有时间或超时,那么当天工作的24小时将被省略...这可能是一个极端的极端情况。拥有一个日历表中可用的所有可能日期值的明确列表可以避免这个问题。)


<强>后续

从您的评论中,您可能需要在不同的日期列表和不同的用户列表之间存在交叉产品,然后是工作时间表的外部联接。

   JOIN ( distinct_list_of_dates_r ) r
     ON ( r_in_specified_week )

  CROSS
   JOIN ( distinct_list_of_userid_u ) u
   LEFT

   JOIN mytable t
     ON ( t_userid_matches_u )
    AND ( t_times_matches_r  )

然后GROUP BY来自u的用户ID,而不是来自t。您可能希望将hours_worked返回的NULL值替换为0. MySQL IFNULL函数很方便,IFNULL(expr,0)CASE WHEN expr IS NULL THEN 0 ELSE expr END的简写。如果您想要整个星期的总小时数,而不是个别日期,那么请GROUP BY表达式week_ending,而不是个别日期。