-1

Below is a record table, which contains different events info. How to get the duration of sum(eventB + eventC + eventD) - eventC - 2*eventD within the same date. (Refer below table)

NOTES:

  1. assume eventB only happen once a day, and there will be always one eventC and two eventD happen during the eventB
  2. there can be multiple eventC, eventD within a day
  3. need to calculate the: sum of the duration of (eventB + eventC + eventD) then minus the 1 eventC and 2 eventD duration, which happen between starttime and endtime of eventB.

table and MySQL details feel free to edit it

Basically, need to handle the overlap durations among eventC, enentD and eventB

Can someone please provide me with some code to handle the above case? Thanks a lot

Sample record table:

eventDate event eventStart eventEnd durations
2020-02-01 eventB 2020-02-01 09:10:25 2020-02-01 09:50:25 40
2020-02-01 eventD 2020-02-01 09:15:25 2020-02-01 09:20:25 5
2020-02-01 eventC 2020-02-01 09:30:25 2020-02-01 09:35:25 5
2020-02-01 eventD 2020-02-01 09:40:25 2020-02-01 09:45:25 5
2020-02-01 eventC 2020-02-01 09:55:25 2020-02-01 09:59:25 4

output for date 2020-02-01 will be 44 -->

sum(B + C + D) - C - 2*D = (40) + (5 + 4) + (5 + 5 ) - 5 - 5 -5 = 44

40 : sum of eventB durations

(5+4) is the sum of event C and so on,

-5 , - 5 and -5 is because the one eventC and two eventD happen during the eventB period.

  • What did you try to get this done? – Luuk Mar 28 '22 at 09:04
  • I just want to see how to handle overlapping durations in MySQL to get the first stage of the large data pool? And,, without understanding the process will be hard for the next steps. –  Mar 28 '22 at 09:07

2 Answers2

0

To get all overlapping events, you can do:

select r1.*, r2.event "OverlapsWith"
from record r1
inner join record r2 on r1.eventStart between r2.eventStart and r2.eventEnd

This wil list something like this:

eventDate event eventStart eventEnd durations OverlapsWith
2020-02-01 eventA 2020-02-01 08:05:25 2020-02-01 08:07:25 2 eventA
2020-02-01 eventA 2020-02-01 08:15:25 2020-02-01 08:20:25 5 eventA
2020-02-01 eventD 2020-02-01 09:40:25 2020-02-01 09:45:25 5 eventB
2020-02-01 eventC 2020-02-01 09:30:25 2020-02-01 09:35:25 5 eventB

EDIT: The correct query should have been:

select r1.*, r2.event "OverlapsWith"
from record r1
inner join record r2 on r1.eventStart <= r2.eventEnd
                     and r1.eventEnd >= r2.eventStart 

Because when some event starts and ends during another event, the first query would not select it.

DBFIDDLE

Luuk
  • 12,245
  • 5
  • 22
  • 33
  • thank you! this is helpful. This is a great hit to solve the overlapping portion, will start from here. –  Mar 28 '22 at 09:19
  • I have to admit that this is an easier example than the answer on this question: [how to get series of overlapping events in MySQL](https://stackoverflow.com/questions/25865144/how-to-get-series-of-overlapping-events-in-mysql?noredirect=1&lq=1) – Luuk Mar 28 '22 at 09:20
  • the first step is to find overlap and remove the overlap then. The content in the above link definitely more complex than my current problems. Anyway, I will refer to the above link to see if I can solve the problem... –  Mar 28 '22 at 09:24
  • *`on r1.eventStart between r2.eventStart and r2.eventEnd`* This is not correct - this expression checks for partial overlappings only. If one range posesses in another range completely then this won't be detected. – Akina Mar 28 '22 at 09:26
  • I added the correction (left original query there, and added explanation why it is wrong....) – Luuk Mar 28 '22 at 10:14
0
WITH RECURSIVE
-- enumerate rows within the date ordering by event start
cte1 AS ( SELECT eventDate,
                 eventStart,
                 eventEnd,
                 ROW_NUMBER() OVER (PARTITION BY eventDate ORDER BY eventStart) rn
          FROM record
),
-- process rows, combine previous and current ranges into one range
cte2 AS ( SELECT eventDate,
                 rn, 
                 eventStart xstart, 
                 eventEnd xend
          FROM cte1 
          WHERE rn = 1
          UNION ALL
          SELECT cte1.eventDate,
                 cte1.rn,
                 CASE WHEN cte2.xend < cte1.eventStart
                      THEN cte1.eventStart
                      ELSE cte2.xstart
                      END,
                 GREATEST(cte1.eventEnd, cte2.xend)
          FROM cte2
          JOIN cte1 ON cte1.rn = cte2.rn + 1
                   AND cte1.eventDate = cte2.eventDate
),
-- remove intermediate ranges
cte3 AS ( SELECT eventDate, xstart, MAX(xend) xend
          FROM cte2
          GROUP BY 1, 2
)
-- get needed data
SELECT eventDate,
       SUM(TIMESTAMPDIFF(MINUTE, xstart, xend)) duration
FROM cte3
GROUP BY 1

https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=bf8f354e0a46204ae59246952baf9d87

Akina
  • 39,301
  • 5
  • 14
  • 25
  • thank you for your help, your code works and is organized very well!! –  Mar 28 '22 at 20:30