2010-01-07 7 views
9

tôi có một cơ sở dữ liệu postgres với hàng triệu hàng trong nó, nó có một cột gọi là geom chứa đường biên của một thuộc tính.Postgis - Làm thế nào để tôi kiểm tra kiểu hình học trước khi tôi chèn

sử dụng tập lệnh python i am trích xuất thông tin từ bảng này và chèn lại nó vào bảng mới.

khi tôi chèn trong bảng mới các lỗi kịch bản ra như sau:

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" 

Bảng mới có một ràng buộc kiểm tra enforce_geotype_geom = ((GeometryType (Geom) = 'Polygon' :: text) HOẶC (geom IS NULL)) trong khi bảng cũ không, do đó, im đoán theres dud dữ liệu hoặc đa giác không (có lẽ multipolygon dữ liệu?) Trong bảng cũ. tôi muốn giữ dữ liệu mới dưới dạng đa giác để không chèn bất kỳ thứ gì khác.

Ban đầu tôi đã thử gói truy vấn với xử lý lỗi python chuẩn với hy vọng rằng các hàng geom dud sẽ không thành công nhưng tập lệnh sẽ tiếp tục chạy, nhưng tập lệnh đã được ghi để cam kết ở cuối không phải mỗi hàng sao cho nó không hoạt động . Tôi nghĩ rằng những gì tôi cần làm là lặp qua các hàng geom bảng cũ và kiểm tra loại hình họ là gì để tôi có thể thiết lập có hay không tôi muốn giữ nó hoặc vứt nó đi trước khi tôi chèn vào bảng mới

Làm cách nào tốt nhất để thực hiện việc này?

Trả lời

7

này chút đáng kinh ngạc hữu ích của PostGIS SQL sẽ giúp bạn hình dung nó ra ... có rất nhiều thử nghiệm loại hình ở đây:

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

cảm ơn, sẽ có giải quyết cho một câu trả lời python/postgres lai, nhưng điều này là tuyệt vời để có thể làm điều đó tất cả bên trong postgres. cảm ơn câu trả lời của bạn – ADAM

2

Tùy chọn 1 là tạo một điểm lưu trữ trước mỗi lần chèn và cuộn trở lại điểm truy cập đó nếu số INSERT không thành công.

Tùy chọn 2 là đính kèm biểu thức ràng buộc kiểm tra dưới dạng điều kiện WHERE trên truy vấn ban đầu đã tạo dữ liệu để tránh chọn nó.

Câu trả lời hay nhất phụ thuộc vào kích thước của bảng, số hàng lỗi tương đối và tốc độ và tần suất này được cho là chạy.

+0

Cảm ơn cho câu trả lời. Tôi thích tùy chọn 2 nhưng tôi vẫn cần các dữ liệu khác được chèn ngay cả khi geom không được chèn vào. Bạn có biết làm thế nào tôi chỉ có thể làm một tuyên bố chọn in các loại geom cho mỗi hàng? – ADAM

+0

và để làm rõ cơ sở dữ liệu có khoảng 5 triệu hàng và điều này chỉ chạy 1 lần mỗi tháng để tạo lại dữ liệu và không cần phải nhanh.tôi chưa biết số lượng hàng bị lỗi – ADAM

+1

Bạn có thể thực hiện truy vấn ban đầu (theo tùy chọn 2) như SELECT par_id, street_add, title_no, chủ sở hữu, au_name, ua_name, CASE WHEN ((geometrytype (geom) = 'POLYGON' :: văn bản) HOẶC (geom IS NULL)) THEN geom ELSE null END AS geom FROM oldtable; để thay thế null cho các giá trị địa lý không "vừa". –

0

Tôi nghĩ rằng bạn có thể sử dụng ST_CollectionExtract - Cho một (đa) hình học , trả về một (đa) hình học chỉ bao gồm các phần tử của kiểu được chỉ định.

Tôi sử dụng nó khi chèn kết quả của ST_Intersection, ST_Dump ngắt mọi đa giác, tập hợp thành hình học riêng lẻ. Sau đó ST_CollectionExtract (theGeom, 3) loại bỏ bất cứ điều gì nhưng đa giác:

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

Tham số thứ hai trên 3 có thể là: 1 == POINT, 2 == LINESTRING, 3 == POLYGON