\c gis postgres ----------- Collect city polygons CREATE TABLE osm_places AS SELECT osm_id, place, 'polygon'::text AS g_type, -- geometry_type max(CASE WHEN regexp_replace(population, '[ .,]+', '', 'g') ~ '^\d+$' THEN regexp_replace(population, '[ .,]+', '', 'g')::int ELSE NULL END ) AS population, ST_Buffer(ST_Transform(ST_Collect(way),4326), 0) AS way, coalesce(max("name"), max("name:en")) AS name FROM planet_osm_polygon WHERE place IN ('city', 'town', 'village', 'hamlet', 'isolated_dwelling') GROUP BY osm_id, place; ----------- Collect city nodes INSERT INTO osm_places SELECT osm_id, place, 'point'::text AS g_type, -- geometry_type CASE WHEN regexp_replace(population, '[ .,]+', '', 'g') ~ '^\d+$' THEN regexp_replace(population, '[ .,]+', '', 'g')::int ELSE NULL END AS population, ST_Transform(way,4326) AS way, coalesce("name", "name:en") AS name FROM planet_osm_point WHERE place IN ('city', 'town', 'village', 'hamlet', 'isolated_dwelling'); CREATE INDEX osm_places_gist_idx ON osm_places USING gist (way); -- Update node population with polygon population where -- the polygon duplicates the node and node has no population UPDATE osm_places SET population = q.max_population FROM ( SELECT n.osm_id node_id, greatest(p.population, n.population) max_population FROM osm_places n, osm_places p WHERE p.g_type='polygon' AND n.g_type='point' AND ST_Contains(p.way, n.way) AND (strpos(n.name, p.name) > 0 OR strpos(p.name, n.name) > 0) ) q WHERE g_type='point' AND osm_id = q.node_id; -- Delete polygons where exists a node within it with the same name DELETE FROM osm_places WHERE g_type='polygon' AND osm_id IN (SELECT p.osm_id FROM osm_places n, osm_places p WHERE p.g_type='polygon' AND n.g_type='point' AND ST_Contains(p.way, n.way) AND (strpos(n.name, p.name) > 0 OR strpos(p.name, n.name) > 0)); -- Convert [multi]polygons to points - for further faster requests "is city in region" ALTER TABLE osm_places ADD COLUMN center geometry; UPDATE osm_places p SET center = ( CASE WHEN ST_Contains(way, ST_Centroid(way)) -- true for 99% of polygons THEN ST_Centroid(way) -- for the rest 1% of city polygons choose arbitrary point as a center ELSE ( SELECT (ST_DumpPoints(way)).geom FROM osm_places WHERE osm_id = p.osm_id LIMIT 1 ) END); CREATE INDEX osm_places_center_gist_idx ON osm_places USING gist (center); DROP INDEX osm_places_gist_idx; ALTER TABLE osm_places DROP COLUMN way;