[postgis-users] Building Heirarchical Topology
Paul Ramsey
pramsey at cleverelephant.ca
Wed Feb 8 11:24:17 PST 2023
Hello users, a question! But first all the setup.
Starting from a base set of data, census blocks, which come with a nice heirarchical key, so it's easy to create contiguous collections just by struncating the key and grouping.
Here's an example key (the column is called geoid20): 530019501001
OK, so let's start just building a topology and associated topogeoms for the blocks. Original simple features geometry table is 'block20', new topogeom table is 'block20_topo'.
SELECT CreateTopology('census', 6599);
CREATE TABLE block20_topo (geoid20 text);
SELECT AddTopoGeometryColumn(
'census',
'public',
'block20_topo',
'topo',
'POLYGON'
);
All good! Now we load the simple features data into the topology and get topogeoms at the same time (magic).
-- Load 463 blocks in one tract, ~15seconds
INSERT INTO block20_topo (geoid20, topo)
SELECT
geoid20, toTopoGeom(geom, 'census', 1)
FROM block20
WHERE geoid20 LIKE '53001950100%';
Still, good, keeping things small, just one tract of 463 blocks.
OK, now hierarchy. Blocks can be formed up into groups. PostGIS topology supports heirarchy by letting one build up "parent" topogeoms where each parent item is made up of "child" topogeoms. In this case the block groups will be made up of blocks.
CREATE TABLE blockgroup20_topo (bgid20 text);
SELECT AddTopoGeometryColumn(
'census',
'public',
'blockgroup20_topo',
'topo',
'POLYGON',
1 -- layer_id of the blocks
);
So far so good: make table, add topogeom for the parent groups, and specify in the function the layer_id of the children.
Now, how to build and insert a parent topogeom into the blockgroup20_topo table?
WITH elms AS (
SELECT left(geoid20,14) AS blkid,
GetTopoGeomElements(topo) AS elm
FROM block20_topo
WHERE geoid20 LIKE '53001950100101%'
)
INSERT INTO blockgroup20_topo (bgid20, topo)
SELECT blkid AS bgid20,
CreateTopoGeom(
'census',
3, -- polygon
2, -- blockgroup20_topo layer_id
TopoElementArray_Agg(elm)
) AS topo
FROM elms
GROUP BY 1
This would seem the most likely way, getting all the elements from the relevant children using GetTopoGeomElements(), group them into one array with TopoElementArray_Agg() and finally create the topogeom with CreateTopoGeom(). But it fails with an error.
ERROR: TopoGeom element layer do not match TopoGeom child layer
Just changing the layer_id in the CreateTopoGeom() to 1 doesn't fix it, because though it successfully creates a topogeom, the restrictions in the topo column blockgroup20_topo correctly stop it from inserting a topogeom that references layer_id 1 into a column that is built for layer_id 2.
Thoughst?
P
More information about the postgis-users
mailing list