The question was originally tagged for sql server and only after my answer was changed to postgresql
I added a comment about that at the bottom of the answer
For sql server you could do it by getting for each row
- the lowest starttime but not before the prior stX
- the highest endtime until the next stX
and then group by on that
Here is a complete example
The query that works with your sample data looks like this
select s.username,
isnull(tstart.StartTime, s.StartTime) as StartTime,
tend.EndTime
from status s
outer apply ( select top 1
s2.StartTime
from status s2
outer apply ( select top 1 s3.StartTime
from status s3
where s3.username = s.username
and s3.StartTime < s.StartTime
and s3.NewState = 'stX'
order by s3.StartTime desc
) s4
where s2.username = s.username
and s2.StartTime < s.StartTime
and (s4.StartTime is null or s2.StartTime > s4.StartTime)
order by s2.StartTime
) tstart
outer apply ( select top 1
s2.EndTime
from status s2
where s2.username = s.username
and s2.EndTime >= s.EndTime
and s2.NewState = 'stX'
order by s2.EndTime
) tend
group by s.username,
isnull(tstart.StartTime, s.StartTime),
tend.EndTime
order by isnull(tstart.StartTime, s.StartTime)
And it returns this as result
| username |
StartTime |
EndTime |
| joe |
08:00:00.0000000 |
11:00:00.0000000 |
| alice |
08:30:00.0000000 |
null |
| joe |
11:20:00.0000000 |
18:50:00.0000000 |
EDIT for postgresql
I don't know postgresql so I don't know if this query will work like it is written. You may have to adapt it for postgresql, it will be possible it is just a different dialect of sql
here are some helpfull links
What is the equivalent Syntax for Outer Apply in PostgreSQL
How to limit rows in PostgreSQL SELECT
What is the PostgreSQL equivalent for ISNULL()