MYSQL&;PHP计算特定日期的总小时数,并排除重叠小时数

MYSQL&;PHP计算特定日期的总小时数,并排除重叠小时数,php,mysql,database,select-query,Php,Mysql,Database,Select Query,我有一个MYSQL任务表,其中每个任务都有一个日期、开始时间、结束时间和用户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`, `

我有一个MYSQL任务表,其中每个任务都有一个日期、开始时间、结束时间和用户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”,这很好,但我想排除重叠时间。在我给出的示例中,当第二条记录中3-4之间的小时被排除时,结果应为“05:00”,因为该小时已存在于第1条记录中2-4之间

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


我希望我把问题说清楚示例

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

当累积数大于0时,则包括与上一次的差异。如果等于0,则它是新时间段的开始,因此不添加任何内容

下面是一个查询示例,通过不跟踪
user\u 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;

SQL FIDLE是否显示它正在工作。

任务之间是否可能存在间隙?预期结果是什么样的?此外,通常最好将日期和时间存储为单个entity@PatrickQ是的,这是可能的(即TaskA 04:00-06:00,TaskB 07:00-08:00),在这种情况下,总时间将为3小时,因为从(04:00-06:00)开始是2小时,(07:00-08:00)开始是1小时。@草莓是的,您可以在单个实体中存储,但不会有任何区别。我给出的示例的预期结果是5小时。这可能是更好的代码。因此,编写一个查询,只返回每个任务的开始和结束时间。循环遍历结果数组,对于每一行,将
start
end
之间的差异添加到
$totalHours
变量中。然后,如果当前
结束
和下一个
开始
之间的差值为负值,则从
$totalHours
中减去该值。如果任务可能并非总是在一小时内开始(例如,从
5:25开始),那么在计算差异之前最好将其转换为秒。您是genius bro,感谢它按预期工作(:,但我的问题是,有没有其他方法可以不使用嵌套的选择查询来执行此操作?@Hadi.M有一种方法,但它速度较慢,而且同样复杂!