【问题标题】:Calculating working hours for each weekday between date range计算日期范围之间每个工作日的工作时间
【发布时间】:2014-10-07 21:53:47
【问题描述】:

我有一个表timeandattandance,包含以下字段

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 之间的差异是否超过一天,那么这些工作时间将分开两天而不是一天。

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

【问题讨论】:

  • 所有这些列都与问题相关吗?

标签: mysql sql date datetime


【解决方案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 年 9 月 28 日星期日开始,持续整整两周,包括 2014 年 10 月 11 日星期六的工作时间。 (re 的值可以从rb 导出为整数天数,得到 14 天,`rb + INTERVAL 13 DAY)

仅报告这些日期或这些日期之间的工作时间。在给定日期没有任何工作“时间”的给定用户 ID 将不会返回该日期的行。 (查询可以很容易地调整为返回范围内所有日期的所有员工的行,并返回零。)

没有包含所有日期值的“cal”日历表,我们可以从表本身获得范围内的不同日期值列表;对于表中的大量或行,这可能是相对昂贵的操作。这不会返回未出现在 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。您可能希望用 0 替换从 hours_worked 返回的 NULL 值。MySQL IFNULL 函数很方便,IFNULL(expr,0)CASE WHEN expr IS NULL THEN 0 ELSE expr END 的简写。如果您想要整周的总小时数,而不是单个日期,请在 week_ending 表达式上执行 GROUP BY,而不是在单个日期上。

【讨论】:

  • spencer7593 非常感谢您抽出宝贵时间。这并不能解决我的整个问题。我需要得到一周内所有日子的工作时间,而且我还需要避免遗漏的问题。如果您能提供完整的解决方案并进行修改,那就太好了。
猜你喜欢
  • 2016-07-23
  • 1970-01-01
  • 2012-02-13
  • 2010-09-20
  • 1970-01-01
  • 2018-08-03
  • 2014-10-20
相关资源
最近更新 更多