10

我有一个包含数百万行的 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"

新表有一个检查约束 enforce_geotype_geom = ((geometrytype(geom) = 'POLYGON'::text) OR (geom IS NULL)) 而旧表没有,所以我猜测有无用数据或非多边形(可能是多多边形数据?) 在旧表中。我想将新数据保留为多边形,所以不想插入任何其他内容。

最初,我尝试使用标准 python 错误处理来包装查询,希望 dud geom 行会失败,但脚本会继续运行,但脚本已被编写为在最后提交而不是每一行,因此它不起作用。

我认为我需要做的是遍历旧表 geom 行并检查它们是什么类型的几何图形,以便在插入新表之前确定是否要保留它或将其丢弃

解决这个问题的最好方法是什么?

4

3 回答 3

8

这个 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;
于 2010-01-07T23:58:06.753 回答
2

选项 1 是在每次插入之前创建一个保存点,如果失败则回滚到该安全点INSERT

选项 2 是将检查约束表达式作为WHERE条件附加到生成数据的原始查询上,以避免选择它。

最佳答案取决于表的大小、错误行的相对数量以及应该运行的速度和频率。

于 2010-01-07T21:39:45.643 回答
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

于 2015-12-18T12:52:34.730 回答