Search code examples
sqlpostgresqlgeometrypostgis

Create Polygon / MultiLineString from linestrings based on their id


I have two tables like this:

lines:
line_id|    geometry
-------------------
1      |    ....
2      |    ....
3      |    ....
4      |    ....
5      |    ....
6      |    ....

(The geometry column is filled up in the lines table)

polygons:
    poly_id |    line_id 
    --------------------
    1       |       1     
    1       |       2     
    1       |       3        
    1       |       4        
    2       |       3       
    2       |       5      
    2       |       6        
    2       |       7       

As you can see in the polygon table I have the line_id-s of the lines that makes up a polygon. What I do is, I make a new table with only one record per poly_id:

SELECT DISTINCT(poly_id) 
INTO polygons_new
FROM polygons;

SELECT AddGeometryColumn('polygons_new','geom',23700,'POLYGON',2);

After this, I would like to fill up the geom column, but so far I couldn't accomplish this. What I've tried is something like this:

UPDATE polygons_new
SET geom = (SELECT ST_Collect(SELECT geometry FROM lines as a, polygons as b WHERE a.line_id = b.line_id))

The problem with this is that it returns more than one row in the subquery. Is there a way to do this task?


Solution

  • Have you tried using, ST_Collect, ST_MergeLine and then create the polygon using ST_MakePolygon? The following example will give you an idea of what I am talking about:

    WITH j (id,geom) AS (
      VALUES (1,'SRID=4326;LINESTRING(30 10, 10 30)'),
             (1,'SRID=4326;LINESTRING(10 30, 40 40)'),
             (1,'SRID=4326;LINESTRING(40 40, 30 10)'),
             (2,'SRID=4326;LINESTRING(50 60, 60 20)'),
             (2,'SRID=4326;LINESTRING(60 20, 45 45)'),
             (2,'SRID=4326;LINESTRING(45 45, 50 60)')
    ) 
     SELECT 
      ST_MakePolygon(
        ST_LineMerge(
          ST_Collect(geom))) 
    FROM j
    GROUP BY id
    

    enter image description here

    EDIT: In case only a MULTILINESTRINGsuffices, just use ST_Collect (see comments):

    WITH j (id,geom) AS (
      VALUES (1,'SRID=4326;LINESTRING(30 10, 10 30)'),
             (1,'SRID=4326;LINESTRING(10 30, 40 40)'),
             (1,'SRID=4326;LINESTRING(40 40, 30 10)'),
             (2,'SRID=4326;LINESTRING(50 60, 60 20)'),
             (2,'SRID=4326;LINESTRING(60 20, 45 45)'),
             (2,'SRID=4326;LINESTRING(45 45, 50 60)')
    ) 
    SELECT ST_Collect(geom)
    FROM j
    GROUP BY id;
    

    enter image description here