I'm using PostgreSQL 9.2 and SSRS 3.0. I'm trying to calculate the difference in non-overlapping time entries in a timesheet.
My data looks like this:
I would like this to return:
I can get the overlapping minutes 635, but am having trouble with the not overlapping, 605 minutes.
Best Answer
Working with this setup:
Total duration without redundancy
Your numbers indicate you just want the total duration without counting same ranges of time multiple times. Not trivial, but can be done with pure SQL rather efficiently:
Explanation:
Beginning at subquery
sub1
, first order rows bystart_time
. While being at it, I actually useORDER BY start_time, end_time DESC
hoping to help performance a bit. But that's unimportant.The custom frame definition (
ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
) allows to compute the maximumend_time
for the previous row with the window aggregate functionmax()
with . If the currentstart_time
is later, we have agap
.In
sub2
count the gaps to form islands. (All rows with the same count of gaps live on the sameisland
(can be aggregated to one gap-less range).The rest is simple, in
sub3
compute the size of eachisland
(duration
), and get the total in the outerSELECT
.Related:
Only ranges without overlap
non-overlapping time entries
like you wrote, can be interpreted in various ways. Excluding all ranges that overlap (consider only ranges of time that are covered exactly once) is hard to solve with pure SQL.The special difficulty is that the "difference" of two ranges can produce two disjoint ranges if the one is a sub-range of the other, like the Postgres manual states for range functions:
I would therefore solve the problem procedurally. Iterate though rows ordered by
start_time
And compare each range to the remaining hopeful range from the last round.This plpgsql function sums all non-overlapping time ranges (or parts of ranges):
SQL Fiddle
db<>fiddle here
Should be fast, too, because a single scan of the table (or index) is enough.
I added some basic ASCII art to visualize
IF
cases. That should help to understand.