In a mysql database (ver.5.7.15) I’ve got the following table named operation_list
containing the following data: id (autoincrement integer, primary key), operation_date_time (datetime), operation (enumerated values: START,STOP), so the table looks like that:
+------+---------------------+-----------+ | id | operation_date_time | operation | +------+---------------------+-----------+ | 1 | 2000-01-01 06:30:45 | START | | 2 | 2000-01-01 07:45:00 | STOP | | 3 | 2000-01-01 08:18:12 | START | | 4 | 2000-01-01 11:23:58 | STOP | | 5 | 2000-01-01 15:45:01 | START | | 6 | 2000-01-01 19:01:33 | STOP | +------+---------------------+-----------+
Now, assuming that the first row is always a START, the last ROW is always a STOP, the STOP is always placed after a START, I need to retrieve the time difference between START and STOP in seconds. Hence, I need to write an SQL that would produce the following recordset:
+------+---------------------+-----------+ | id | operation_date_time | duration | +------+---------------------+-----------+ | 1 | 2000-01-01 06:30:45 | 4455 | | 3 | 2000-01-01 08:78:12 | 11146 | | 5 | 2000-01-01 15:45:01 | 11792 | +------+---------------------+-----------+
Where 4455 is equivalent to 1 hour, 14 minutes and 15 seconds, 11146 is equivalent to 3 hours, 5 minutes and 46 seconds, 11792 is equivalent to 3 hours, 16 minutes and 32 seconds, and so on.
What’s the best way to do it in a single SQL statement without creating additional tables or dedicated scripting?
Advertisement
Answer
This works IN mysql 5.X
But it is uglier as in 8.0
SELECT MIN(id) id ,MIN(`operation_date_time`) `operation_date_time` ,MAX(diff) duration FROM (SELECT id , IF(`operation` = 'START', 0,TIME_TO_SEC(TIMEDIFF(`operation_date_time`, @datetime))) diff ,IF(`operation` = 'START', @count := @count + 1,@count := @count) groupby ,@datetime := `operation_date_time` `operation_date_time` FROM (SELECT * FROM timetable ORDER by `operation_date_time` ASC) t1, (SELECT @datetime := NOW()) a, (SELECT @count := 0) b) t2 GROUP by groupby;
CREATE TABLE timetable ( `id` INTEGER, `operation_date_time` VARCHAR(19), `operation` VARCHAR(5) ); INSERT INTO timetable (`id`, `operation_date_time`, `operation`) VALUES ('1', '2000-01-01 06:30:45', 'START'), ('2', '2000-01-01 07:45:00', 'STOP'), ('3', '2000-01-01 08:18:12', 'START'), ('4', '2000-01-01 11:23:58', 'STOP'), ('5', '2000-01-01 15:45:01', 'START'), ('6', '2000-01-01 19:01:33', 'STOP');✓ ✓
SELECT MIN(id) id ,MIN(`operation_date_time`) `operation_date_time` ,MAX(diff) duration FROM (SELECT id , IF(`operation` = 'START', 0,TIME_TO_SEC(TIMEDIFF(`operation_date_time`, @datetime))) diff ,IF(`operation` = 'START', @count := @count + 1,@count := @count) groupby ,@datetime := `operation_date_time` `operation_date_time` FROM (SELECT * FROM timetable ORDER by `operation_date_time` ASC) t1, (SELECT @datetime := NOW()) a, (SELECT @count := 0) b) t2 GROUP by groupby;id | operation_date_time | duration -: | :------------------ | -------: 1 | 2000-01-01 06:30:45 | 4455 3 | 2000-01-01 08:18:12 | 11146 5 | 2000-01-01 15:45:01 | 11792
db<>fiddle here