Postgis - Как проверить тип геометрии перед вставкой
У меня есть база данных postgres с миллионами строк в ней есть столбец под названием geom, который содержит границу свойства.
используя скрипт python, я извлекаю информацию из этой таблицы и повторно вставляю ее в новую таблицу.
когда я вставляю в новую таблицу, скрипт выдает следующее:
Traceback (most recent call last):
File "build_parcels.py", line 258, in <module>
main()
File "build_parcels.py", line 166, in main
update_cursor.executemany("insert into parcels (par_id, street_add, title_no, proprietors, au_name, ua_name, geom) VALUES (%s, %s, %s, %s, %s, %s, %s)", inserts)
psycopg2.IntegrityError: new row for relation "parcels" violates check constraint "enforce_geotype_geom"
новая таблица имеет ограничение Check enforce_geotype_geom = ((geometrytype(Геом) = 'полигон'::text), либо (гем-нуль)) в то время как старая таблица не делает, поэтому я предполагаю, что есть данные dud или не полигон (возможно, данные multipolygon? в старом столе. я хочу сохранить новые данные как полигон, поэтому не хочу вставлять что-либо еще.
Первоначально я попытался обернуть запрос стандартной обработкой ошибок python в надежде , что строки DUD geom потерпят неудачу, но скрипт будет продолжать работать, но скрипт был написан для фиксации в конце не каждой строки, поэтому он не работает.
Я думаю, что мне нужно чтобы сделать это, повторите старые строки таблицы geom и проверьте, какой тип геометрии они, чтобы я мог установить, хочу ли я сохранить его или выбросить его, прежде чем вставлять в новую таблицу
каков наилучший способ сделать это?
3 ответов
этот удивительно полезный бит PostGIS SQL должен помочь вам понять это... здесь есть много тестов типа геометрии:
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
--
-- $Id: cleanGeometry.sql 2008-04-24 10:30Z Dr. Horst Duester $
--
-- cleanGeometry - remove self- and ring-selfintersections from
-- input Polygon geometries
-- http://www.sogis.ch
-- Copyright 2008 SO!GIS Koordination, Kanton Solothurn, Switzerland
-- Version 1.0
-- contact: horst dot duester at bd dot so dot ch
--
-- This is free software; you can redistribute and/or modify it under
-- the terms of the GNU General Public Licence. See the COPYING file.
-- This software is without any warrenty and you use it at your own risk
--
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CREATE OR REPLACE FUNCTION cleanGeometry(geometry)
RETURNS geometry AS
$BODY$DECLARE
inGeom ALIAS for ;
outGeom geometry;
tmpLinestring geometry;
Begin
outGeom := NULL;
-- Clean Process for Polygon
IF (GeometryType(inGeom) = 'POLYGON' OR GeometryType(inGeom) = 'MULTIPOLYGON') THEN
-- Only process if geometry is not valid,
-- otherwise put out without change
if not isValid(inGeom) THEN
-- create nodes at all self-intersecting lines by union the polygon boundaries
-- with the startingpoint of the boundary.
tmpLinestring := st_union(st_multi(st_boundary(inGeom)),st_pointn(boundary(inGeom),1));
outGeom = buildarea(tmpLinestring);
IF (GeometryType(inGeom) = 'MULTIPOLYGON') THEN
RETURN st_multi(outGeom);
ELSE
RETURN outGeom;
END IF;
else
RETURN inGeom;
END IF;
------------------------------------------------------------------------------
-- Clean Process for LINESTRINGS, self-intersecting parts of linestrings
-- will be divided into multiparts of the mentioned linestring
------------------------------------------------------------------------------
ELSIF (GeometryType(inGeom) = 'LINESTRING') THEN
-- create nodes at all self-intersecting lines by union the linestrings
-- with the startingpoint of the linestring.
outGeom := st_union(st_multi(inGeom),st_pointn(inGeom,1));
RETURN outGeom;
ELSIF (GeometryType(inGeom) = 'MULTILINESTRING') THEN
outGeom := multi(st_union(st_multi(inGeom),st_pointn(inGeom,1)));
RETURN outGeom;
ELSIF (GeometryType(inGeom) = '<NULL>' OR GeometryType(inGeom) = 'GEOMETRYCOLLECTION') THEN
RETURN NULL;
ELSE
RAISE NOTICE 'The input type % is not supported %',GeometryType(inGeom),st_summary(inGeom);
RETURN inGeom;
END IF;
End;$BODY$
LANGUAGE 'plpgsql' VOLATILE;
Вариант 1-Создать точку сохранения перед каждой вставкой и вернуться к этой точке сохранения, если INSERT
не удается.
Вариант 2-прикрепить выражение ограничения проверки как WHERE
условие исходного запроса, который произвел данные, чтобы избежать его выбора вообще.
лучший ответ зависит от размера таблиц, относительного количества ошибочных строк и того, как быстро и часто это должно выполняться.
Я думаю, вы можете использовать ST_CollectionExtract - учитывая (multi)геометрию, возвращает (multi)геометрию, состоящую только из элементов указанного типа.
Я использую его при вставке результатов ST_Intersection, ST_Dump разбивает любые многоугольники, коллекции на отдельные геометрии. Тогда ST_CollectionExtract (theGeom, 3)
отбрасывает все, кроме полигонов:
ST_CollectionExtract((st_dump(ST_Intersection(data.polygon, grid.polygon))).geom, )::geometry(polygon, 4326)
второй параметр выше 3
можно: 1 == POINT, 2 == LINESTRING, 3 == POLYGON