Pregunta

Tengo una base de datos Postgres con millones de filas, tiene una columna llamada Geom que contiene el límite de una propiedad.

Usando un script de Python, estoy extrayendo la información de esta tabla y vuelvo a insertarla en una nueva tabla.

Cuando me inserto en la nueva tabla, el script se excita con lo siguiente:

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 nueva tabla tiene una restricción de verificación aplicada_geotype_geom = ((geometryType (geom) = 'polygon' :: text) o (geom es nula)) mientras que la tabla anterior no, por lo que supongo que hay datos de DUD o no polígono (quizás los datos multipoligón ?) En la vieja mesa. Quiero mantener los nuevos datos como polígono, así que no quiero insertar nada más.

Inicialmente, intenté envolver la consulta con el manejo estándar de errores de Python con la esperanza de que las filas DUD Geom fallaran, pero el script seguiría ejecutando, pero el script se ha escrito para comprometerse al final, no cada fila, por lo que no funciona.

Creo que lo que necesito hacer es iterar a través de las viejas filas de geom de la mesa y verificar qué tipo de geometría son para que pueda establecer si quiero mantenerlo o tirarlo antes de insertar en la nueva mesa.

¿Cuál es la mejor manera de ir sobre esto?

¿Fue útil?

Solución

Este poco asombrosamente útil de Postgis SQL debería ayudarlo a resolverlo ... Hay muchas pruebas de tipo de geometría aquí:

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

Otros consejos

La opción 1 es crear un punto de guardado antes de cada inserción y volver a ese safePoint si un INSERT falla.

La opción 2 es adjuntar la expresión de restricción de verificación como un WHERE condición en la consulta original que produjo los datos para evitar seleccionarlos en absoluto.

La mejor respuesta depende del tamaño de las tablas, el número relativo de filas defectuosas y qué tan rápido y a menudo se supone que se debe funcionar.

Creo que puedes usarSt_collectionExtract - Dada una (multi) geometría, devuelve una geometría (multi) que consiste solo en elementos del tipo especificado.

Lo uso al insertar los resultados de una ST_INTERSECTION, ST_DUMP rompe cualquier colección multi-polifonal, en geometría individual. Después ST_CollectionExtract (theGeom, 3) descarta cualquier cosa menos polígonos:

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

El segundo parámetro anterior 3 puede ser: 1 == POINT, 2 == LINESTRING, 3 == POLYGON

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top