Postgis - Как проверить тип геометрии перед вставкой - PullRequest
10 голосов
/ 08 января 2010

У меня есть база данных 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"

В новой таблице есть проверочное ограничение forcece_geotype_geom = ((geometrytype (geom) = 'POLYGON' :: text) OR (geom IS NULL)), в то время как в старой таблице нет, поэтому я предполагаю, что у них нет данных или нет полигонов возможно, данные о мультиполигонах?) в старой таблице. я хочу сохранить новые данные как многоугольник, поэтому не хочу ничего вставлять.

Первоначально я попытался обернуть запрос стандартной обработкой ошибок Python, надеясь, что строки dud geom потерпят неудачу, но скрипт продолжит работу, но скрипт был написан для фиксации в конце не каждой строки, поэтому он не работает.

Я думаю, что мне нужно сделать, это пройтись по строкам старой таблицы geom и проверить, к какому типу геометрии они относятся, чтобы я мог определить, хочу ли я сохранить ее или выбросить, прежде чем вставить в новую таблицу

Какой лучший способ сделать это?

Ответы [ 3 ]

8 голосов
/ 08 января 2010

Этот удивительно полезный кусочек 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 $1;
  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;
2 голосов
/ 08 января 2010

Вариант 1 - создать точку сохранения перед каждой вставкой и выполнить откат к этой безопасной точке в случае сбоя INSERT.

Вариант 2 заключается в том, чтобы прикрепить выражение контрольного ограничения в качестве условия WHERE к исходному запросу, который создал данные, чтобы вообще не выбирать их.

Лучший ответ зависит от размера таблиц, относительного количества ошибочных строк и от того, насколько быстро и часто это должно выполняться.

0 голосов
/ 18 декабря 2015

Я думаю, что вы можете использовать ST_CollectionExtract - Учитывая (мульти) геометрию, возвращает (мульти) геометрию, состоящую только из элементов указанного типа.

Я использую его при вставке результатов 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

...