2010-01-07 2 views
9

Ich habe eine Postgres-Datenbank mit Millionen von Zeilen darin es hat eine Spalte namens Geom, die die Grenze einer Eigenschaft enthält.Postgis - Wie überprüfe ich den Geometrietyp, bevor ich eine Einfügung mache

Mit einem Python-Skript entziehe ich die Informationen aus dieser Tabelle und setze sie erneut in eine neue Tabelle ein.

wenn ich stecke in der neuen Tabelle, die die Skript Fehler aus mit dem folgenden:

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" 

Die neue Tabelle hat eine Check-Bedingung enforce_geotype_geom = ((GeometryType (geom) = 'POLYGON' :: Text) OR (Geom IS NULL)) während die alte Tabelle nicht, so its rates ther Daten oder Nicht-Polygon (vielleicht multipolygon Daten?) in der alten Tabelle. Ich möchte die neuen Daten als Polygon beibehalten, damit nichts anderes eingefügt werden kann.

Zuerst habe ich versucht, die Abfrage mit Standard-Python-Fehlerbehandlung mit der Hoffnung, dass die Blind Geom Zeilen würden fehlschlagen, aber das Skript würde weiter laufen, aber das Skript wurde geschrieben, um am Ende nicht jede Zeile zu committen, so dass es nicht funktioniert .

Ich denke, was ich tun muss, ist durch die alten Tabelle Geom Zeilen durchlaufen und überprüfen, welche Art von Geometrie sie sind, so kann ich feststellen, ob ich es behalten oder wegwerfen will, bevor ich in die neue Tabelle einfügen

Was ist der beste Weg, um darüber zu gehen?

Antwort

7

Diese erstaunlich nützlich wenig PostGIS SQL sollten Sie es helfen herauszufinden, ... es gibt viele Geometrietypprüfungen hier:

-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
-- 
-- $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

danke, hätte sich für eine Hybrid-Python/Postgres-Antwort entschieden, aber das ist erstaunlich, um alles in Postgres zu tun. Danke für deine Antwort – ADAM

2

Option 1 besteht darin, vor jedem Einfügen einen Sicherungspunkt zu erstellen und einen Rollback auf diesen Sicherpunkt auszuführen, wenn ein INSERT fehlschlägt.

Option 2 besteht darin, den Check-Einschränkungsausdruck als WHERE-Bedingung an die ursprüngliche Abfrage anzufügen, die die Daten erzeugt hat, damit sie überhaupt nicht ausgewählt werden.

Die beste Antwort hängt von der Größe der Tabellen, der relativen Anzahl fehlerhafter Zeilen und davon ab, wie schnell und oft dies ausgeführt werden soll.

+0

Danke für die Antwort. Ich mag die Option 2, aber ich brauche immer noch die anderen Daten eingefügt, auch wenn die Geom nicht eingefügt wird. Weißt du, wie ich eine Select-Anweisung ausführen kann, die den Geom-Typ für jede Zeile ausgibt? – ADAM

+0

und um die Datenbank zu klären hat etwa 5 Millionen Zeilen und dies wird nur 1 Mal pro Monat ausgeführt, um die Daten zu regenerieren und muss nicht schnell sein.Ich kenne noch nicht die Anzahl der fehlerhaften Zeilen – ADAM

+1

Sie könnten die ursprüngliche Abfrage (wie Option 2) wie SELECT par_id, street_add, title_no, proprietors, au_name, ua_name, CASE WHEN ((geometrytype (geom) = 'POLYGON') :: text) ODER (geom IS NULL)) DANN geom ELSE null ENDE AS geom FROM oldtable; NULL für Geom-Werte ersetzen, die nicht "passen". –

0

Ich glaube, Sie ST_CollectionExtract verwenden - Bei Geometrie ein (multi) , gibt eine (Multi-) Geometrie zurück, die nur aus Elementen des angegebenen Typs besteht.

Ich benutze es beim Einfügen der Ergebnisse einer ST_Intersection, bricht ST_Dump alle Multi-Polygon, Sammlungen in einzelne Geometrie. Dann verwirft ST_CollectionExtract (theGeom, 3) alles andere als Polygone:

ST_CollectionExtract((st_dump(ST_Intersection(data.polygon, grid.polygon))).geom,)::geometry(polygon, 4326)

Der zweite Parameter oben 3 kann sein: 1 == POINT, 2 == LINESTRING, 3 == POLYGON