2010-01-07 65 views
9

我有一個包含數百萬行的postgres數據庫,它有一個名爲geom的列,其中包含屬性的邊界。Postgis - 我如何在插入之前檢查幾何類型

使用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)= '多邊形' ::文)OR (geom IS NULL)),而舊錶不會,所以即時猜測舊錶中的數據或非多邊形(可能是多邊形數據?)。我想保留新的數據作爲多邊形,所以不想插入其他任何東西。

最初我試圖用標準的python錯誤處理來包裝查詢,希望dud geom行會失敗,但腳本會繼續運行,但腳本已經寫在最後不提交,因此它不起作用。

我想我需要做的是遍歷舊錶格幾何行,並檢查它們是什麼類型的幾何,所以我可以確定是否要保留它或丟棄之前,我插入到新表

這是怎麼回事呢?

回答

7

這驚人的有用的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; 
+0

謝謝,本來會解決混合蟒蛇/ postgres的答案,但這是令人驚訝的是能夠做到這一切在postgres裏面。感謝您的回答 – ADAM 2010-01-08 00:26:28

2

選項1是在每次插入之前創建一個保存點,並在INSERT失敗時回滾到該安全點。

選項2是將檢查約束表達式作爲WHERE條件附加在產生數據的原始查詢上以避免選擇它。

最好的答案取決於表格的大小,錯誤行的相對數量以及這個應該運行的速度和頻率。

+0

感謝您的回答。我喜歡選項2,但即使geom未插入,我仍然需要插入其他數據。你知道我可以做一個select語句來打印每行的geom類型嗎? – ADAM 2010-01-07 21:45:17

+0

並澄清數據庫有大約500萬行,這只是每月運行1次來重新生成數據,並且不需要很快。我還不知道錯誤行的數量 – ADAM 2010-01-07 21:46:58

+1

您可以執行原始查詢(按照選項2),如 SELECT par_id,street_add,title_no,proprietors,au_name,ua_name,CASE WHEN((geometrytype(geom)='POLYGON' :: text)OR(geom IS NULL))然後geom ELSE null END AS geom FROM oldtable; 將null替換爲不適合的geom值。 – 2010-01-07 23:12:16

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

相關問題