У меня есть таблица, в которой хранятся записи с задачами, статусом и временем срабатывания:
Таблица 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);
Теперь я хочу получить таблицу для всех задач
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
Вы можете обнаружить "ненормальные" данные, добавив следующее в список выражений выбора
, 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
Примечание: любые "незамкнутые" интервалы будут отмечены как ненормальные; без более сложной и дорогостоящей проверки начала и конца интервалов, чтобы дифференцировать "открытые" с "недействительными", это, вероятно, лучшее, что можно сделать. Сумма, используемая для дополнительной проверки целостности, равная -1, может намекать на открытый интервал, но также может указывать на ошибочное двойное начало.
A
составлять 3600 секунд (1 час) вместо 7200 секунд (2 часа)? ... начало2018-03-07 20:00:00
конец2018-03-07 21:30:00
минус 30 минут перерыва.