【问题标题】:MYSQL & PHP calculate total hours in specific date and exclude overlaps hoursMYSQL & PHP 计算特定日期的总小时数并排除重叠小时数
【发布时间】:2014-05-31 23:44:42
【问题描述】:

我有一个任务的 MYSQL 表,其中每个任务都有日期、开始时间、结束时间和 user_id。我想计算特定日期的总小时数。

表结构

CREATE TABLE tasks
    (`id` int,`user_id` int, `title` varchar(30), `task_date` datetime, `start` time, `end` time)
;

INSERT INTO tasks
    (`id`,`user_id`, `title`,`task_date`, `start`, `end`)
VALUES
    (1,10, 'Task one','2013-04-02', '02:00:00', '04:00:00'),
    (2,10, 'Task two','2013-04-02', '03:00:00', '06:00:00'),
    (3,10, 'Task three.','2013-04-02','06:00:00', '07:00:00');

MYSQL 查询

select  TIME_FORMAT(SEC_TO_TIME(sum(TIME_TO_SEC(TIMEDIFF( end, start)))), "%h:%i") AS diff
FROM tasks
where task_date="2013-04-02"

得到的结果是“06:00”小时,这很好,但我想排除重叠时间。在示例中,我给出的结果应该是“05:00”小时,因为第二条记录中 3-4 之间的小时被排除在外,因为这个小时已经存在于 2-4 之间的第一条记录中。

  • 第一条记录 2=>4 = 2 小时
  • 第 2 条记录 3=>6 = 3 小时 3-1 小时=2(1 小时是第 1 条和第 2 条记录之间的重叠小时)
  • 第三个 6=>7=1

总共是 5 小时

我希望我的问题说清楚了。 示例 http://sqlfiddle.com/#!2/05dd8/2

【问题讨论】:

  • 任务之间是否可能存在间隙?
  • 期望的结果是什么样的?此外,将日期和时间存储为单个实体通常会更好
  • @PatrickQ 是的,这是可能的(即 TaskA 04:00 - 06:00,TaskB 07:00 - 08:00),在这种情况下,总时间为 3 小时,因为从 (04:00 - 06:00) 是 2 小时,(07:00 - 08:00) 是 1 小时。
  • @Strawberry 是的,您可以将其存储在单个实体中,但这没有任何区别。我给出的示例的预期结果是 5 小时。
  • 这可能在代码中做得更好。所以编写一个查询,只返回每个任务的开始和结束时间。循环遍历结果数组,对于每一行,将startend 之间的差异添加到$totalHours 变量中。然后,如果当前end 和下一个start 之间的差为负,则从$totalHours 中减去该值。如果任务可能并不总是在一小时后开始(例如,从 5:25 开始),那么在计算差异之前转换为秒可能会更好。

标签: php mysql database select-query


【解决方案1】:

这是一个使用变量的想法(在其他数据库中,CTE 和窗口函数会使这更容易)。这个想法是首先列出所有时间——开始和结束。然后,跟踪开始和停止的累积次数。

当累计数大于0时,则包括与上一次的差值。如果等于 0,那么它是一个新时间段的开始,所以什么都不加。

这是一个查询示例,通过不跟踪 user_id 中的更改,对您的数据进行了一些简化:

select user_id, TIME_FORMAT(SEC_TO_TIME(sum(secs)), '%h:%i')
from (select t.*, 
             @time := if(@sum = 0, 0, TIME_TO_SEC(TIMEDIFF(start, @prevtime))) as secs,
             @prevtime := start,
             @sum := @sum + isstart
      from ((select user_id, start, 1 as isstart
             from tasks t
            ) union all
            (select user_id, end, -1
             from tasks t
            )
           ) t cross join
           (select @sum := 0, @time := 0, @prevtime := 0) vars
      order by 1, 2
     ) t
group by user_id;

Here 是一个 SQL Fiddle,显示它正在工作。

【讨论】:

  • 你是天才兄弟,谢谢它按预期工作(:,但我的问题是有另一种方法可以在不使用嵌套选择查询的情况下做到这一点吗?
  • @Hadi.M 有办法,但速度较慢,而且同样复杂!
猜你喜欢
  • 2017-01-08
  • 2022-01-15
  • 1970-01-01
  • 1970-01-01
  • 2023-03-11
  • 2016-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多