わかりました。本番環境で使用する前に、あらゆる方法でこれをテストすることを強くお勧めします。特に、1つの期間に複数のオーバーラップがある場合に何が起こるかをテストしてください。
このクエリが行うことは、各期間の期間と、より高いIDを持つ他の期間とどの程度の重複が存在するかを計算することです。
select
t1.id,
t1.start_time,
t1.end_time,
t1.end_time - t1.start_time as duration,
sum(
if(t2.start_time < t1.start_time and t2.end_time > t1.end_time , t1.end_time - t1.start_time, 0) -- t2 completely around t1
+ if(t2.start_time >= t1.start_time and t2.end_time <= t1.end_time , t2.end_time - t2.start_time, 0) -- t2 completely within t1
+ if(t2.start_time < t1.start_time and t2.end_time > t1.start_time and t2.end_time < t1.end_time , t2.end_time - t1.start_time, 0) -- t2 starts before t1 starts and overlaps partially
+ if(t2.start_time < t1.end_time and t2.end_time > t1.end_time and t2.start_time > t1.start_time, t1.end_time - t2.start_time, 0) -- t2 starts before t1 ends and overlaps partially
) as overlap
from
times t1
left join times t2 on
t2.id > t1.id -- t2.id is greater than t1.id
and (
(t2.start_time < t1.start_time and t2.end_time > t1.end_time ) -- t2 completely around t1
or (t2.start_time >= t1.start_time and t2.end_time <= t1.end_time ) -- t2 completely within t1
or (t2.start_time < t1.start_time and t2.end_time > t1.start_time) -- t2 starts before t1 starts and overlaps
or (t2.start_time < t1.end_time and t2.end_time > t1.end_time ) -- t2 starts before t1 ends and overlaps
)
group by
t1.id
つまり、最終的に必要なのはこれです:
select
sum(t.duration) - sum(t.overlap) as filtered_duration
from
(
OTHER QUERY HERE
) as t
したがって、最終的には次のクエリがあります:
select
sum(t.duration) - sum(t.overlap) as filtered_duration
from
(
select
t1.id,
t1.start_time,
t1.end_time,
t1.end_time - t1.start_time as duration,
sum(
if(t2.start_time < t1.start_time and t2.end_time > t1.end_time , t1.end_time - t1.start_time, 0) -- t2 completely around t1
+ if(t2.start_time >= t1.start_time and t2.end_time <= t1.end_time , t2.end_time - t2.start_time, 0) -- t2 completely within t1
+ if(t2.start_time < t1.start_time and t2.end_time > t1.start_time and t2.end_time < t1.end_time , t2.end_time - t1.start_time, 0) -- t2 starts before t1 starts and overlaps partially
+ if(t2.start_time < t1.end_time and t2.end_time > t1.end_time and t2.start_time > t1.start_time, t1.end_time - t2.start_time, 0) -- t2 starts before t1 ends and overlaps partially
) as overlap
from
times t1
left join times t2 on
t2.id > t1.id -- t2.id is greater than t1.id
and (
(t2.start_time < t1.start_time and t2.end_time > t1.end_time ) -- t2 completely around t1
or (t2.start_time >= t1.start_time and t2.end_time <= t1.end_time ) -- t2 completely within t1
or (t2.start_time < t1.start_time and t2.end_time > t1.start_time) -- t2 starts before t1 starts and overlaps
or (t2.start_time < t1.end_time and t2.end_time > t1.end_time ) -- t2 starts before t1 ends and overlaps
)
group by
t1.id
) as t