GIS開発研究所 > PostGISの不正ポリゴンを修正|ST_IsValidとST_MakeValid
2026年7月23日
•約5分で読めます
PostGISへ取り込んだポリゴンの自己交差やリング不正を、ST_IsValid・ST_IsValidDetail・ST_MakeValidで調査します。修正前後の形状型と面積を比較し、元データを残したまま安全に補正するSQLと再発防止策を解説します。
ShapefileやGeoJSONをPostGISへ取り込んだ後、交差判定や面積計算でエラーになったことはありませんか。見た目では普通のポリゴンでも、境界線が自己交差していたり、リングが正しく閉じていなかったりすることがあります。
このようなデータは「不正なgeometry」と呼ばれます。まずST_IsValidで検出し、理由と場所を確認してからST_MakeValidを使います。いきなり全件を自動修正しないことが大切です。
基本の流れは次のとおりです。
ST_MakeValidを試すST_MakeValidは便利ですが、1つのPolygonがMultiPolygonやGeometryCollectionへ変わる場合があります。修正後の型確認を省略しないようにしましょう。
まず件数を確認します。
SELECT
count(*) FILTER (WHERE ST_IsValid(geom)) AS valid_count,
count(*) FILTER (WHERE NOT ST_IsValid(geom)) AS invalid_count,
count(*) FILTER (WHERE geom IS NULL) AS null_count
FROM land_parcels;
不正レコードを一覧にします。
SELECT
id,
ST_IsValidReason(geom) AS reason
FROM land_parcels
WHERE NOT ST_IsValid(geom)
ORDER BY id
LIMIT 100;
よくある理由には次のものがあります。
Self-intersection 境界線が自分自身と交差しているRing Self-intersection リングの中で線が交差しているHole lies outside shell 穴が外周の外にあるNested shells 外周同士の包含関係が不正理由だけでなく、問題が起きている位置も取得できます。
CREATE TEMP TABLE invalid_geometry_points AS
SELECT
p.id,
d.reason,
d.location
FROM land_parcels p
CROSS JOIN LATERAL ST_IsValidDetail(p.geom) d
WHERE NOT d.valid;
この一時テーブルをQGISへ読み込むと、不正箇所を点として確認できます。元のポリゴンと重ねると、どの頂点を直すべきか判断しやすくなります。
本番geometryを直接更新せず、最初は修正結果を別列へ保存します。
ALTER TABLE land_parcels
ADD COLUMN geom_fixed geometry;
UPDATE land_parcels
SET geom_fixed = ST_MakeValid(geom)
WHERE NOT ST_IsValid(geom);
修正後の型を確認します。
SELECT
GeometryType(geom) AS before_type,
GeometryType(geom_fixed) AS after_type,
count(*)
FROM land_parcels
WHERE geom_fixed IS NOT NULL
GROUP BY GeometryType(geom), GeometryType(geom_fixed)
ORDER BY before_type, after_type;
Polygon列へGeometryCollectionをそのまま戻すことはできません。面データだけを取り出す場合は、業務要件を確認した上でST_CollectionExtractを使います。
UPDATE land_parcels
SET geom_fixed = ST_Multi(
ST_CollectionExtract(
ST_MakeValid(geom),
3
)
)
WHERE NOT ST_IsValid(geom);
3はポリゴン要素を意味します。線や点へ崩れた部分を除外してよいかは、データの用途によって判断が必要です。
geometryが有効になっても、面積が大きく変わっていないか確認します。
SELECT
id,
ST_Area(geom) AS before_area,
ST_Area(geom_fixed) AS after_area,
CASE
WHEN ST_Area(geom) = 0 THEN NULL
ELSE abs(ST_Area(geom_fixed) - ST_Area(geom))
/ ST_Area(geom)
END AS change_rate
FROM land_parcels
WHERE geom_fixed IS NOT NULL
ORDER BY change_rate DESC NULLS LAST
LIMIT 50;
面積変化が大きいレコードは、QGISで目視確認します。地番、管理区域、課金面積などに使うデータは、自動修正だけで確定させない方が安心です。
古い記事では、ポリゴン修正にST_Buffer(geom, 0)が紹介されることがあります。単純な自己交差を直せる場合はありますが、不正geometryの修正を目的とした関数ではありません。
現在は、理由を確認した上でST_MakeValidを使う方が意図を伝えやすく、修正結果も検証しやすくなります。
外部データを定期的に取り込む場合は、本番テーブルへ直接追加せず、ステージングテーブルを挟みます。
外部ファイル
↓
ステージングテーブル
↓ 妥当性・SRID・型を確認
本番テーブル
本番テーブルへチェック制約を設定する方法もあります。
ALTER TABLE land_parcels
ADD CONSTRAINT land_parcels_geom_valid
CHECK (ST_IsValid(geom));
複雑なgeometryでは検査コストがかかるため、登録頻度やデータ量を確認して導入しましょう。
不正ポリゴンを見つけたら、次の点を確認します。
ST_IsValidReasonで原因を見るST_IsValidDetailで問題箇所を見るST_MakeValid後の型を確認する**「有効になった」ことと「業務上正しい形になった」ことは同じではありません。**修正後のデータをどう使うかまで確認しましょう。
PostGISのデータ品質改善やGISデータ移行でお困りの場合は、GIS開発を無料相談する。
千葉県出身。10歳の頃からプログラミングを始め、ゲーム、Webサイト、ロボット、スマホアプリなどを制作。大阪大学基礎工学部情報科学科で情報工学と統計学を学び、大学時代はAIを研究。大学在学中にWeb広告代理店でのインターンや人材系Webサービスの立ち上げを経験し、卒業後はフリーランスエンジニアとしてGISシステム、データ基盤構築、Webシステムの開発に従事。10年以上のWebアプリ開発・データ分析経験を基に、2023年9月に株式会社ビットライトを設立し、現場業務の仕組み化からデータ基盤構築、データ活用支援までを一気通貫で支援。