【问题标题】:Calculating difference on datetime row betwen rows on the same table计算同一表上各行之间日期时间行的差异
【发布时间】:2018-09-14 15:00:52
【问题描述】:

我有一个表格,其中包含触发时的任务、状态和时间记录:

表格工作:

+-------------+------------+---------------------+-----+
| task        | status     | stime               | id  |
+-------------+------------+---------------------+-----+
| A           | 1          | 2018-03-07 20:00:00 | 1   |
| A           | 2          | 2018-03-07 20:30:00 | 2   |
| A           | 1          | 2018-03-07 21:00:00 | 3   |
| A           | 3          | 2018-03-07 21:30:00 | 4   |
| B           | 1          | 2018-03-07 22:30:00 | 5   |
| B           | 3          | 2018-03-07 23:30:00 | 6   |
+-------------+------------+---------------------+-----+

状态 1 表示开始,2 - 暂停,3 - 结束

然后我需要计算每个任务花费了多少时间,不包括暂停(状态 = 2)。我就是这样做的:

SELECT t1.id, t1.task,
SUM(timestampdiff(second,IFNULL( 
(SELECT MAX(t2.stime) FROM tblwork t2  WHERE t2.task='B' AND t2.stime< t1.stime) ,t1.stime),t1.stime)) myTimeDiffSeconds
FROM tblwork t1 
WHERE t1.task='B' and (t1.status = 1 or t1.status = 3);

现在我想获取所有任务的表格

SELECT t1.id, t1.task,
SUM(timestampdiff(second,IFNULL( 
(SELECT MAX(t2.stime) FROM tblwork t2  WHERE t2.stime< t1.stime) ,t1.stime),t1.stime)) myTimeDiffSeconds
FROM tblwork t1 
WHERE (t1.status = 1 or t1.status = 3) GROUP BY t1.taks

我得到这个结果:

+-------------+------------+---------------------+
| task        | id         | mytimedifference    |
+-------------+------------+---------------------+
| A           | 1          | 3600                |   
| B           | 3          | 2421217             |
+-------------+------------+---------------------+

A 计算正确 B 错误,应该是 3600 秒,但我不明白为什么。

【问题讨论】:

  • "A 计算正确 B 错误" 任务 A 的 mytimedifference 不应该是 3600 秒(1 小时)而不是 7200 秒(2 小时)吗? ... 开始 2018-03-07 20:00:00 结束 2018-03-07 21:30:00 减去 30 分钟的休息时间。
  • 不太确定 id 的相关性应该是什么; B 从不与源数据中的 id = 3 相关联。
  • 是的,你是对的。抱歉,打错字了。
  • 我假设列 id 是带有 auto_increment 选项的主键?在结束前还有不止一个休息时间吗?
  • and 之前可以有更多的中断。见这个例子sqlfiddle.com/#!9/050a41/1

标签: mysql datetime time datediff timestampdiff


【解决方案1】:

假设每次暂停和结束总是有一个开始,这样的事情不是更直接吗?

SELECT t.task
   , SUM(TO_SECONDS(t.stime) 
         * CASE WHEN t.status IN (1) THEN -1
                WHEN t.status IN (2, 3) THEN 1
                ELSE 0
           END
     ) AS totalTimeSecs
FROM tblwork AS task
GROUP BY t.task

我不太确定来自 TO_SECONDS() 的值对于当前时间戳有多大;但是如果它们在求和时是一个问题,如果可以更改为

   , SUM((TO_SECONDS(t.stime) - some_constant_just_before_or_at_your_earliest_seconds)
         * CASE WHEN t.status IN (1) THEN -1
                WHEN t.status IN (2, 3) THEN 1
                ELSE 0
           END
     ) AS totalTimeSecs

您可以通过将以下内容添加到选择表达式列表中来检测“异常”数据

, CASE WHEN SUM(CASE 
                WHEN t.status IN (1) THEN -1 
                WHEN t.status IN (2, 3) THEN 1 
                ELSE 0 END
              ) = 0 
       THEN 'OK' 
       ELSE 'ABNORMAL' 
   END AS integrityCheck

注意:任何“未闭合”的区间都将被标记为异常;没有更复杂和昂贵的开始和结束检查间隔以区分“打开”和“无效”,这可能是可以做到的最好的。 用于附加“integrityCheck”的总和等于 -1 可能暗示一个开放式区间,但也可能表示错误的双启动。

【讨论】:

  • hm... 如果 taks 包含所有三种状态,则无法正常运行。参见计算 D sqlfiddle.com/#!9/050a41/1
  • D 在我看来是无效数据;它有一个“开始”、“暂停”、“停止”,但在“暂停”之后缺少一个恢复的“开始”。
  • 你是对的。数据异常,因为每个任务都必须以状态 3 结束。非常感谢,它运行良好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-09-25
  • 1970-01-01
  • 2020-02-14
  • 2010-11-07
  • 2021-11-25
  • 2011-08-01
相关资源
最近更新 更多