[postgis-users] How can I split a polyline?
Michael Fuhr
mike at fuhr.org
Tue Mar 7 16:37:02 PST 2006
On Tue, Mar 07, 2006 at 04:01:54PM -0500, Fay Du wrote:
> My next question is, after I split a line, how can I keep all attributes
> for new lines? The attributes are from clients. Column names and numbers
> are random. Can I get column names of a table?
Are you looking for something like the following? The query would
specify whatever columns it wants and the functions would generate
as many output rows as necessary for each matching row:
CREATE FUNCTION split_geom(geometry) RETURNS SETOF geometry AS $$
SELECT GeometryN($1, n) FROM generate_series(1, NumGeometries($1)) AS g(n);
$$ LANGUAGE sql IMMUTABLE STRICT;
CREATE FUNCTION split_points(geometry) RETURNS SETOF geometry AS $$
SELECT PointN($1, n) FROM generate_series(1, NumPoints($1)) AS g(n);
$$ LANGUAGE sql IMMUTABLE STRICT;
SELECT id, label, AsText(geom) FROM foo;
id | label | astext
----+-------+----------------------------------------------
1 | abc | MULTILINESTRING((1 2,3 4),(5 6,7 8))
2 | def | MULTILINESTRING((11 12,13 14),(15 16,17 18))
(2 rows)
SELECT id, label, AsText(split_geom(geom)) FROM foo;
id | label | astext
----+-------+-------------------------
1 | abc | LINESTRING(1 2,3 4)
1 | abc | LINESTRING(5 6,7 8)
2 | def | LINESTRING(11 12,13 14)
2 | def | LINESTRING(15 16,17 18)
(4 rows)
SELECT id, label, AsText(split_points(split_geom(geom))) FROM foo;
id | label | astext
----+-------+--------------
1 | abc | POINT(1 2)
1 | abc | POINT(3 4)
1 | abc | POINT(5 6)
1 | abc | POINT(7 8)
2 | def | POINT(11 12)
2 | def | POINT(13 14)
2 | def | POINT(15 16)
2 | def | POINT(17 18)
(8 rows)
Only SQL functions can be used as I've shown, as a set-returning
function in the select list; functions written in other languages
like PL/pgSQL will cause such queries to fail with the following
error:
ERROR: set-valued function called in context that cannot accept a set
The PostgreSQL documentation says in "Query Language (SQL) Functions":
Currently, functions returning sets may also be called in the
select list of a query. For each row that the query generates
by itself, the function returning set is invoked, and an output
row is generated for each element of the function's result set.
Note, however, that this capability is deprecated and may be
removed in future releases.
If that worries you then you could do something like this, although
it's not as flexible as the above examples:
CREATE FUNCTION foo_split() RETURNS SETOF foo AS $$
DECLARE
row foo%ROWTYPE;
newrow foo%ROWTYPE;
geom geometry;
BEGIN
FOR row IN SELECT * FROM foo LOOP
newrow := row;
FOR i IN 1 .. NumGeometries(row.geom) LOOP
geom := GeometryN(row.geom, i);
FOR j IN 1 .. NumPoints(geom) LOOP
newrow.geom := PointN(geom, j);
RETURN NEXT newrow;
END LOOP;
END LOOP;
END LOOP;
RETURN;
END;
$$ LANGUAGE plpgsql STABLE;
SELECT id, label, AsText(geom) FROM foo_split();
id | label | astext
----+-------+--------------
1 | abc | POINT(1 2)
1 | abc | POINT(3 4)
1 | abc | POINT(5 6)
1 | abc | POINT(7 8)
2 | def | POINT(11 12)
2 | def | POINT(13 14)
2 | def | POINT(15 16)
2 | def | POINT(17 18)
(8 rows)
--
Michael Fuhr
More information about the postgis-users
mailing list