You could use the window functions first_value()
and last_value()
in a single CASE
statement:
SELECT *
, CASE WHEN ts IN ( first_value(created_at) OVER w
, last_value(created_at) OVER w)
THEN created_at::time::interval ELSE NULL END AS period
FROM tbl
WINDOW w AS (ORDER BY created_at rows BETWEEN UNBOUNDED PRECEDING
AND UNBOUNDED FOLLOWING);
Special requirement here: you need to adjust the frame definition for the last_value()
call. By default it is:
RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
But you need:
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
The first_value()
call would work with the default frame, but can use the same as well.
I also simplified computation of period
. Your definition coincides with the time
component of a timestamp.
Just cast to time
to "truncate" the date part: created_at::time
.
Casting to interval
after that is just to return the same data type as your original query.
The result will be ordered by created_at
automatically due to the current implementation of window functions. But do not rely on that. If you need sorted output, add to the end explicitly:
ORDER BY created_at