patternsqlMinor
MySQL: sum time ranges exluding overlapping ones
Viewed 0 times
timerangesmysqloverlappingsumonesexluding
Problem
I need to sum up the time which results from multiple time ranges. For example - we have enter / exit ranges of some office:
Query has to:
Expected result in this case is 8:00 (8:00 to 12:00 + 14:00 to 18:00)
Example table structure:
Expected result:
Table structure:
Example inserts
Query has to:
- Exclude overlapping ranges (8:00 - 10:00)
- Exclude "missing" part (12:00 - 14:00)
Expected result in this case is 8:00 (8:00 to 12:00 + 14:00 to 18:00)
Example table structure:
DAY | TIME_ENTER | TIME_EXIT
2016-01-01 | 08:00 | 10:00
2016-01-01 | 08:00 | 12:00
2016-01-01 | 14:00 | 18:00Expected result:
DAY | TOTAL
2016-01-01 | 08:00Table structure:
CREATE TABLE Registry
(`Date` DATE,
`Enter` TIME,
`Exit` TIME);Example inserts
INSERT INTO Registry
VALUES
('2016-01-01', '08:00', '09:00'),
('2016-01-01', '08:00', '12:00'),
('2016-01-01', '14:00', '18:00')Solution
Original
You want to sum up all time ranges, except those that fit inside other time ranges on the same day:
SqlFiddle
Edit: the above solution won't always work, as pointed out by ypercube. The following solution should cover all scenarios.
Revised solution
SqlFiddle
You want to sum up all time ranges, except those that fit inside other time ranges on the same day:
SELECT DATE_FORMAT(DAY, '%Y-%m-%d')
,TIME_FORMAT(SEC_TO_TIME(TIME_TO_SEC(
SUM(TIMEDIFF(TIME_EXIT,TIME_ENTER))
)), '%H:%i') AS Total
FROM Table1 AS t
WHERE NOT EXISTS (
SELECT *
FROM Table1
WHERE DAY = t.DAY
AND TIME_ENTER = t.TIME_EXIT
# not the same row; if you have an ID column, use it instead
# eg AND NOT ID = t.ID
AND NOT (TIME_ENTER = t.TIME_ENTER AND TIME_EXIT = t.TIME_EXIT)
)
GROUP BY DAY;SqlFiddle
Edit: the above solution won't always work, as pointed out by ypercube. The following solution should cover all scenarios.
Revised solution
SELECT DATE_FORMAT(DAY, '%Y-%m-%d')
,TIME_FORMAT(SEC_TO_TIME(TIME_TO_SEC(
SUM(TIMEDIFF(TIME_EXIT,TIME_ENTER))
)), '%H:%i') AS Total
FROM (
SELECT DISTINCT t.DAY
,(SELECT MIN(TIME_ENTER) FROM Table1
WHERE TIME_EXIT BETWEEN t.TIME_ENTER AND t.TIME_EXIT) AS TIME_ENTER
,(SELECT MAX(TIME_EXIT) FROM Table1
WHERE TIME_ENTER BETWEEN t.TIME_ENTER AND t.TIME_EXIT) AS TIME_EXIT
FROM Table1 t
) AS o
GROUP BY DAY;SqlFiddle
Code Snippets
SELECT DATE_FORMAT(DAY, '%Y-%m-%d')
,TIME_FORMAT(SEC_TO_TIME(TIME_TO_SEC(
SUM(TIMEDIFF(TIME_EXIT,TIME_ENTER))
)), '%H:%i') AS Total
FROM Table1 AS t
WHERE NOT EXISTS (
SELECT *
FROM Table1
WHERE DAY = t.DAY
AND TIME_ENTER <= t.TIME_ENTER AND TIME_EXIT >= t.TIME_EXIT
# not the same row; if you have an ID column, use it instead
# eg AND NOT ID = t.ID
AND NOT (TIME_ENTER = t.TIME_ENTER AND TIME_EXIT = t.TIME_EXIT)
)
GROUP BY DAY;SELECT DATE_FORMAT(DAY, '%Y-%m-%d')
,TIME_FORMAT(SEC_TO_TIME(TIME_TO_SEC(
SUM(TIMEDIFF(TIME_EXIT,TIME_ENTER))
)), '%H:%i') AS Total
FROM (
SELECT DISTINCT t.DAY
,(SELECT MIN(TIME_ENTER) FROM Table1
WHERE TIME_EXIT BETWEEN t.TIME_ENTER AND t.TIME_EXIT) AS TIME_ENTER
,(SELECT MAX(TIME_EXIT) FROM Table1
WHERE TIME_ENTER BETWEEN t.TIME_ENTER AND t.TIME_EXIT) AS TIME_EXIT
FROM Table1 t
) AS o
GROUP BY DAY;Context
StackExchange Database Administrators Q#127092, answer score: 3
Revisions (0)
No revisions yet.