ST_MakePolygon — Creates a Polygon from a shell and optional list of holes.
geometry ST_MakePolygon(geometry linestring);
geometry ST_MakePolygon(geometry outerlinestring, geometry[] interiorlinestrings);
Creates a Polygon formed by the given shell and optional array of holes. Input geometries must be closed LineStrings (rings).
Variant 1: Accepts one shell LineString.
Variant 2: Accepts a shell LineString and an array of inner (hole) LineStrings. A geometry array can be constructed using the PostgreSQL array_agg(), ARRAY[] or ARRAY() constructs.
                 
               | 
              |
| 
                 This function does not accept MultiLineStrings. Use ST_LineMerge to generate a LineString, or ST_Dump to extract LineStrings.  | 
            
            
            This function supports 3d and will not drop the z-index.
        
Create a Polygon from a 2D LineString.
SELECT ST_MakePolygon( ST_GeomFromText('LINESTRING(75 29,77 29,77 29, 75 29)'));
        Create a Polygon from an open LineString, using ST_StartPoint and ST_AddPoint to close it.
SELECT ST_MakePolygon( ST_AddPoint(foo.open_line, ST_StartPoint(foo.open_line)) )
FROM (
  SELECT ST_GeomFromText('LINESTRING(75 29,77 29,77 29, 75 29)') As open_line) As foo;
        Create a Polygon from a 3D LineString
SELECT ST_AsEWKT( ST_MakePolygon( 'LINESTRING(75.15 29.53 1,77 29 1,77.6 29.5 1, 75.15 29.53 1)')); st_asewkt ----------- POLYGON((75.15 29.53 1,77 29 1,77.6 29.5 1,75.15 29.53 1))
Create a Polygon from a LineString with measures
SELECT ST_AsEWKT( ST_MakePolygon( 'LINESTRINGM(75.15 29.53 1,77 29 1,77.6 29.5 2, 75.15 29.53 2)' )); st_asewkt ---------- POLYGONM((75.15 29.53 1,77 29 1,77.6 29.5 2,75.15 29.53 2))
Create a donut Polygon with an extra hole
SELECT ST_MakePolygon( ST_ExteriorRing( ST_Buffer(ring.line,10)), ARRAY[ ST_Translate(ring.line, 1, 1), ST_ExteriorRing(ST_Buffer(ST_Point(20,20),1)) ] ) FROM (SELECT ST_ExteriorRing( ST_Buffer(ST_Point(10,10),10,10)) AS line ) AS ring;
Create a set of province boundaries with holes
    representing lakes.  The input is a table of
    province Polygons/MultiPolygons and a table of water linestrings.
    Lines forming lakes are determined by using ST_IsClosed.
    The province linework is extracted by using
    ST_Boundary.
    As required by ST_MakePolygon,
    the boundary is forced to be a single LineString by using ST_LineMerge.
    (However, note that if a province has more than one region or has islands
    this will produce an invalid polygon.)
    Using a LEFT JOIN ensures all provinces are included even if they have no lakes.
    
                 
               | 
              |
| 
                 The CASE construct is used because passing a null array into ST_MakePolygon results in a NULL return value.  | 
            
SELECT p.gid, p.province_name,
	CASE WHEN array_agg(w.geom) IS NULL
	THEN p.geom
	ELSE  ST_MakePolygon( ST_LineMerge(ST_Boundary(p.geom)),
                        array_agg(w.geom)) END
FROM
	provinces p LEFT JOIN waterlines w
		ON (ST_Within(w.geom, p.geom) AND ST_IsClosed(w.geom))
GROUP BY p.gid, p.province_name, p.geom;
        Another technique is to utilize a correlated subquery and the ARRAY() constructor that converts a row set to an array.
SELECT p.gid,  p.province_name,
    CASE WHEN EXISTS( SELECT w.geom
        FROM waterlines w
        WHERE ST_Within(w.geom, p.geom)
        AND ST_IsClosed(w.geom))
    THEN ST_MakePolygon(
        ST_LineMerge(ST_Boundary(p.geom)),
        ARRAY( SELECT w.geom
            FROM waterlines w
            WHERE ST_Within(w.geom, p.geom)
            AND ST_IsClosed(w.geom)))
    ELSE p.geom
    END AS geom
FROM provinces p;