2010-01-07 4 views
9

У меня есть база данных postgres с миллионами строк, в ней есть столбец с именем geom, который содержит границу свойства.Postgis - Как проверить тип геометрии перед вставкой

using python script Я извлекаю информацию из этой таблицы и снова вставляю ее в новую таблицу.

, когда я вставить в новую таблицу ошибок сценариев с следующее:

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" 

Новая таблица имеет проверочное ограничение enforce_geotype_geom = ((geometrytype (геом) = «ПОЛИГОН» :: текст) ИЛИ (geom IS NULL)), тогда как в старой таблице нет, поэтому я предполагаю данные dud data или non polygon (возможно, данные multipolygon?) в старой таблице. Я хочу сохранить новые данные в виде многоугольника, поэтому не хочу вставлять что-либо еще.

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

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

Каков наилучший способ обойти это?

ответ

7

Это удивительно полезные немного 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; 
+0

спасибо, согласился бы на гибридный ответ python/postgres, но это удивительно, чтобы иметь возможность делать все это внутри postgres. спасибо за Ваш ответ – ADAM

2

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

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

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

+0

Спасибо за ответ. Мне нравится вариант 2, но мне все еще нужны другие данные, вставленные, даже если геометрия не вставлена. Вы знаете, как я могу просто сделать оператор select, который печатает тип геометрии для каждой строки? – ADAM

+0

и для уточнения базы данных имеет около 5 миллионов строк, и это выполняется только один раз в месяц, чтобы восстановить данные и не нужно быстро.Я еще не знаю количество ошибочных строк – ADAM

+1

Вы можете сделать исходный запрос (по выбору 2), например SELECT par_id, street_add, title_no, владельцы, au_name, ua_name, CASE WHEN ((geometrytype (geom) = 'POLYGON' :: text) ИЛИ (geom IS NULL)) THEN geom ELSE null END AS geom FROM oldtable; , чтобы заменить значение null для значений геометрии, которые не «соответствуют». –

0

Я думаю, что вы можете использовать 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

Смежные вопросы