/posts  ·   /talks  ·   /boat  ·   /#30DayMapChallenge 2020 | 2022  ·  /About

Multies to singleparts in mssql

This writeup serves to purposes:

Dumping a multipart

As a reference, in PostGIS you can achieve this by

select
    id, (st_dump(geom)).*
from
    foo.bar
;

st_dump in PostGIS is a set-returning function and this last query will return records in the form of path, geom.

In SQLServer there is no built-in way but this can be achieved by generating a set of integers corresponding to the number of component geometries and then pulling the respective geometry. So the above query would be something in the line of:

select
    id, n.n, geom.STGeometryN(n.n) as geom
from
    foo.bar
        join (
            select
                row_number() over (order by object_id) as n
            from
                sys.all_objects
        ) n on
            n.n <= geom.STNumGeometries()
;

Build a polygon from a closed LineString

Now this is a bit tricky and I’ve not really dug into the implications on this but at least it seemed to work for my current use case. Again, in PostGIS you’d dump your multipart polygons to singleparts, get the exterior ring with st_exteriorring of the polygon and then call st_buildarea to get the polygon.

select
    id, st_buildarea(st_exteriorring((st_dump(geom)).geom))
from
    foo.bar
;

I ended up finding a solution to this in this StackOverflow question with carefully hand-crafting WKB in a select statement. Meaning:

select
    id,
    geometry::STGeomFromWKB(
        0x01 + 0x03000000 + 0x01000000 +
        substring(
            geom.STAsBinary(), 6, datalength(geom.STAsBinary())
        ), geom.STSrid
    ) as geom
from (
    select
        id, geom.STGeometryN(n.n).STExteriorRing() as geom
    from
        foo.bar
            join (
                select
                    row_number() over (order by object_id) as n
                from
                    sys.all_objects
            ) n on
                n.n <= geom.STNumGeometries()
) f
;

So, yes …