Reputation: 1603
I have a table with a structure like this:
datetime | the_geom | m_status
2017-01-01T00:00:00 | POINT(13.048133,57.798882) | status_1
2017-01-01T00:00:01 | POINT(14.048133,56.798882) | status_1
2017-01-01T00:00:02 | POINT(15.048133,55.798882) | status_1
2017-01-01T00:00:04 | POINT(17.048133,53.798882) | status_2
2017-01-01T00:00:05 | POINT(18.048133,52.798882) | status_2
2017-01-01T00:00:06 | POINT(19.048133,51.798882) | status_2
2017-01-01T00:00:07 | POINT(20.048133,50.798882) | status_1
2017-01-01T00:00:08 | POINT(21.048133,49.798882) | status_1
2017-01-01T00:00:09 | POINT(22.048133,48.798882) | status_3
2017-01-01T00:00:10 | POINT(23.048133,47.798882) | status_3
I would like to group sequential points by m_status into separate Linestrings but only if they are in sequential order following the datetime column.
Any constructive help is appreciated.
PostgreSQL version: PostgreSQL 9.5.2 on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3, 64-bit
edit 1:
Expected output:
id | the_geom | m_status
1 | LINESTRING(13.048133 57.798882, 14.048133 56.798882, 15.048133 55.798882) | status_1
2 | LINESTRING(17.048133 53.798882, 18.048133 52.798882, 19.048133 51.798882) | status_2
3 | LINESTRING(20.048133 50.798882, 21.048133 49.798882) | status_1
4 | LINESTRING(22.048133 48.798882, 23.048133 47.798882) | status_3
edit 2: I don't need the start and end dates for each linestring, however I need some sort of id to know their temporal order (see id in expected output above).
Upvotes: 1
Views: 355
Reputation: 49260
You can use a difference of row numbers approach to classify the groups (run the inner query to see group assignment) and then use ST_MakeLine
to get all those points on to one row.
select ST_MakeLine(the_geom order by datetime) as the_geom, max(m_status) as m_status
from (select t.*,
row_number() over(order by datetime)
-row_number() over(partition by m_status order by datetime) as grp
from tbl t
) t
group by grp
Edit: Based on OP's edit to include row numbers in the output, get the min or max time per group previously identified and use it for ordering.
SELECT row_number() over(ORDER BY min_time) AS id,
ST_MakeLine(the_geom ORDER BY datetime) AS the_geom,
max(m_status) AS m_status
FROM
(SELECT t.*,
min(datetime) over(partition BY grp,m_status) AS min_time
FROM
(SELECT t.*,
row_number() over(ORDER BY datetime) -row_number() over(partition BY m_status ORDER BY datetime) AS grp
FROM tbl t
) t
) t
GROUP BY grp,min_time
Upvotes: 2