I have data which is shown below.
stationName | status | startTime | endTime |
---|---|---|---|
A | normal | 09:00 | 09:10 |
A | normal | 09:10 | 09:20 |
B | normal | 09:30 | 09:40 |
A | normal | 09:30 | 09:40 |
B | normal | 09:40 | 09:45 |
A | warning | 09:40 | 09:45 |
B | warning | 09:45 | 09:55 |
A | alert | 09:45 | 09:55 |
B | normal | 09:55 | 10:05 |
A | alert | 09:55 | 10:05 |
B | normal | 10:05 | 10:15 |
A | normal | 10:05 | 10:15 |
B | normal | 10:15 | 10:25 |
A | normal | 10:15 | 10:25 |
B | normal | 10:25 | 10:35 |
A | normal | 10:25 | 10:35 |
and I want to query data into this structure
stationName | status | startTime | endTime |
---|---|---|---|
A | normal | 09:00 | 09:40 |
A | warning | 09:40 | 09:45 |
A | alert | 09:45 | 10:05 |
A | normal | 10:05 | 10:35 |
B | normal | 09:30 | 09:45 |
B | warning | 09:45 | 09:55 |
B | normal | 09:55 | 10:35 |
My data timeline data is split into many parts, but I want to group it into one.
CodePudding user response:
demo
idea: construct a range, test (startTime,endTime) belong to one specific timestamptz range or not,
then group by stationname, status, range(startTime, endTime) belong to.
I would use timestamptz type for startTime, endTime, tstzrange.
If you construct timerange, then range (23:00,0:00)
is invalid.
table structure:
CREATE TABLE test102 (
stationName text,
status text,
startTime timestamptz,
endTime timestamptz
);
then query:
WITH cte AS (
SELECT
test102.*,
tstzrange(startTime, endTime) tstzrange_se,
tstzrange(i - interval '1 hour', i)
FROM
test102,
generate_series('2022-05-02'::timestamp, '2022-05-02'::timestamp interval '24 hour', interval '1 hour') i
)
SELECT
stationname,
status,
min(startTime),
max(endTime)
FROM
cte
WHERE
tstzrange_se <@ tstzrange
GROUP BY
1,
2,
tstzrange;