2010-01-07 3 views
9

J'ai une base de données postgres avec des millions de lignes, il a une colonne appelée geom qui contient la limite d'une propriété. En utilisant un script python, je suis en train d'extraire les informations de cette table et de les réinsérer dans une nouvelle table.Postgis - Comment puis-je vérifier le type de géométrie avant de faire un insert

lors de l'insertion dans la nouvelle table les bugs de script avec les éléments suivants:

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" 

La nouvelle table a une contrainte de vérification enforce_geotype_geom = ((GeometryType (geom) = 'POLYGONE' :: text) OU (geom IS NULL)) alors que l'ancienne table ne le fait pas, donc je devine qu'il y a des données non converties ou des données non polygonales (peut-être des données multipolygones?) dans l'ancienne table. Je veux garder les nouvelles données sous forme de polygone, donc je ne veux rien ajouter d'autre. Initialement, j'ai essayé d'encapsuler la requête avec la gestion des erreurs python standard avec l'espoir que les lignes de geom ratées échoueraient mais le script continuerait à fonctionner, mais le script a été écrit pour valider à la fin de chaque ligne donc ça ne marche pas .

Je pense que ce que je dois faire est de parcourir les anciennes lignes de la table geom et vérifier quel type de géométrie elles sont afin que je puisse établir si je veux le garder ou le jeter avant de l'insérer dans la nouvelle table

Quelle est la meilleure façon de procéder?

Répondre

7

Ce bit étonnamment utile de PostGIS SQL devrait vous aider à sortir ... il y a beaucoup de tests de type géométrie ici:

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

grâce, aurait réglé pour un python hybride/postgres réponse, mais c'est incroyable de pouvoir le faire tous postgres à l'intérieur. Merci pour votre réponse – ADAM

2

L'option 1 consiste à créer un point de sauvegarde avant chaque insertion et à revenir à ce point de sécurité en cas d'échec d'un INSERT.

L'option 2 consiste à associer l'expression de contrainte de vérification en tant que condition WHERE à la requête d'origine qui a produit les données pour éviter de les sélectionner du tout.

La meilleure réponse dépend de la taille des tables, du nombre relatif de lignes défectueuses et de la rapidité et de la fréquence de cette opération.

+0

Merci pour la réponse. J'aime l'option 2 mais j'ai toujours besoin des autres données insérées même si le geom n'est pas inséré. Savez-vous comment je peux faire une déclaration select qui imprime le type geom pour chaque ligne? – ADAM

+0

et de clarifier la base de données a environ 5millions de lignes et cela ne fonctionne que 1 fois par mois pour régénérer les données et n'a pas besoin d'être rapide.Je ne sais pas encore le nombre de lignes défectueuses – ADAM

+1

Vous pouvez faire la requête originale (selon l'option 2) comme SELECT par_id, street_add, title_no, propriétaires, au_name, ua_name, CAS QUAND ((geometrytype (geom) = 'POLYGON' :: texte) OR (geom IS nULL)) ALORS geom FIN SINON null AS geom DE oldtable; de substituer null pour les valeurs geom qui ne sont pas « aptes ». –

0

Je pense que vous pouvez utiliser ST_CollectionExtract - Étant donné une géométrie (multi) renvoie une géométrie (multi) composée uniquement d'éléments du type spécifié. Je l'utilise lors de l'insertion des résultats d'une ST_Intersection, ST_Dump casse les collections multi-polygones en une géométrie individuelle. Puis ST_CollectionExtract (theGeom, 3) défausse quoi que ce soit mais les polygones:

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

Le second paramètre ci-dessus 3 peut être: 1 == POINT, 2 == LINESTRING, 3 == POLYGON

Questions connexes