计算同一 table 上各行之间日期时间行的差异
Calculating difference on datetime row betwen rows on the same table
我有 table 保存任务、状态和触发时间的记录:
Table tblwork:
+-------------+------------+---------------------+-----+
| 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);
现在我想获得 table 的所有任务
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 秒,但我不明白为什么。
假设每次停顿和结束都有一个开始,这样不是更直接吗?
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
您可以通过将以下内容添加到 select 表达式列表来检测 "abnormal" 数据
, 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
注意:任何"unclosed"区间都会被标记为异常;没有更复杂和昂贵的开始和结束检查间隔以区分 "open" 和 "invalid",这可能是最好的方法。 用于附加 "integrityCheck" 等于 -1 的总和可能暗示一个开放式区间,但也可能表示错误的 double-start。
我有 table 保存任务、状态和触发时间的记录:
Table tblwork:
+-------------+------------+---------------------+-----+
| 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);
现在我想获得 table 的所有任务
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 秒,但我不明白为什么。
假设每次停顿和结束都有一个开始,这样不是更直接吗?
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
您可以通过将以下内容添加到 select 表达式列表来检测 "abnormal" 数据
, 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
注意:任何"unclosed"区间都会被标记为异常;没有更复杂和昂贵的开始和结束检查间隔以区分 "open" 和 "invalid",这可能是最好的方法。 用于附加 "integrityCheck" 等于 -1 的总和可能暗示一个开放式区间,但也可能表示错误的 double-start。