Chapter 08

マルチポリゴンを単一ポリゴンに変換する

boiledorange73
boiledorange73
2020.10.26に更新

はじめに

シェープファイルのデータをインポートしてみよう コマンドライン編シェープファイルのデータをインポートしてみよう GUI編で、国土数値情報(行政区域)のシェープファイルをPostGISにインポートしました。
コマンドライン編の後半で、シェープファイルにはマルチポリゴンはあって、単一ポリゴン(ジオメトリタイプ: POLYGON)が無いことを紹介しました。

国土数値情報(行政区域)については、シェープファイルの仕様で仕方なくマルチポリゴンとしていますが、実質的には単一ポリゴンです。
マルチポリゴンを単一ポリゴンに変換した方が良い場合と、市区町村ごとにマルチポリゴンにした方が良い場合とがあると思いますが、いずれの場合も、なんらかの加工が必要となります。

今回は、マルチポリゴンを単一ポリゴンに分解する方法を示します。

使用する関数

ST_Dump, ST_NumGeometries

マルチポリゴンを単一ポリゴンに分解する

マルチ系ジオメトリを単一ジオメトリにするには、ST_Dumpを使います。

ST_Dumpは、geometry_dump型を返します。この型は、整数配列のpathとジオメトリ型のgeomとからできています。

db=# SELECT name, ST_Dump(geom) AS dump FROM (
  SELECT
    'g1' AS name,
    'MULTIPOLYGON(((0 0, 1 0, 1 1, 0 0)),((2 0, 3 0, 3 1, 2 0)))'::GEOMETRY AS geom
  UNION SELECT
    'g2' AS name,
    'MULTIPOLYGON(((0 2, 1 2, 1 3, 0 2)),((2 2, 3 2, 3 3, 2 2)))'::GEOMETRY AS geom
) AS Q1
 name |                                                                               dump                                                                               
------+------------------------------------------------------------------------------------------------------------------------------------------------------------------
 g1   | ({1},0103000000010000000400000000000000000000000000000000000000000000000000F03F0000000000000000000000000000F03F000000000000F03F00000000000000000000000000000000)
 g1   | ({2},0103000000010000000400000000000000000000400000000000000000000000000000084000000000000000000000000000000840000000000000F03F00000000000000400000000000000000)
 g2   | ({1},0103000000010000000400000000000000000000000000000000000040000000000000F03F0000000000000040000000000000F03F000000000000084000000000000000000000000000000040)
 g2   | ({2},0103000000010000000400000000000000000000400000000000000040000000000000084000000000000000400000000000000840000000000000084000000000000000400000000000000040)
(4 行)

dumpが、整数配列とEWKBとの組み合わせになっているのが分かると思います。

pathとgeomとにバラして、geomはST_AsTextで見やすくして表示してみます。

db=# SELECT name, (dump).path, ST_AsText((dump).geom) FROM (
  SELECT name, ST_Dump(geom) AS dump FROM (
    SELECT
      'g1' AS name,
      'MULTIPOLYGON(((0 0, 1 0, 1 1, 0 0)),((2 0, 3 0, 3 1, 2 0)))'::GEOMETRY AS geom
    UNION SELECT
      'g2' AS name,
      'MULTIPOLYGON(((0 2, 1 2, 1 3, 0 2)),((2 2, 3 2, 3 3, 2 2)))'::GEOMETRY AS geom
  ) AS Q1
) AS Q2;
 name | path |         st_astext          
------+------+----------------------------
 g1   | {1}  | POLYGON((0 0,1 0,1 1,0 0))
 g1   | {2}  | POLYGON((2 0,3 0,3 1,2 0))
 g2   | {1}  | POLYGON((0 2,1 2,1 3,0 2))
 g2   | {2}  | POLYGON((2 2,3 2,3 3,2 2))

ST_Dump以外のカラム

ST_Dump以外のカラムは、マルチ系ジオメトリごとに同じ値となります。上の結果を見ると、nameカラムで'g1'となっている行と'g2'となっている行が複数あることが確認できると思います。

pathフィールド

pathにはマルチ系ジオメトリ内にあったときの順序が1はじまりで入っています。順序はマルチ系ジオメトリごとにユニークになりますが、複数のマルチ系ジオメトリがある場合にはユニークではありません。順序が逆転すると困る場合にはpathは重要になると思いますが、通常は無視してかまいません。

マルチ系ジオメトリ内の単一ジオメトリの数を見る

上の例では、Q1が吐くタプルはふたつだったけれども、最終的には4タプルが出てきました。つまりタプル数が増加する可能性があります。どれぐらい増加するかを事前に見るには、マルチ系ジオメトリごとに、内部に持つ単一ジオメトリを見ます。

db=# SELECT ST_NumGeometries(geom) FROM t1;
 st_numgeometries 
------------------
                1
                1
                1
                1
                1
                1
                1
                1
...

t1のマルチポリゴンは、全て単一ポリゴンをひとつずつ持っていることが分かります。

テーブル t1d を作成して t1 から分解したポリゴンをたたき込む

(以前はt1uとしていましたがt1dに変更します)

db=# CREATE TABLE t1d (
  gid SERIAL PRIMARY KEY,
  n03_001 TEXT,
  n03_002 TEXT,
  n03_003 TEXT,
  n03_004 TEXT,
  n03_007 TEXT,
  geom GEOMETRY(POLYGON, 4612)
);
NOTICE:  CREATE TABLE will create implicit sequence "t1d_gid_seq" for serial column "t1d.gid"
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "t1d_pkey" for table "t1d"
CREATE TABLE

db=# CREATE INDEX ix_t1d_geom ON t1d USING GiST (geom);
CREATE INDEX

ふつうにINSERT INTOでOKです。

db=# INSERT INTO t1d(n03_001,n03_002,n03_003,n03_004,n03_007,geom)
  SELECT n03_001,n03_002,n03_003,n03_004,n03_007,(ST_Dump(geom)).geom AS geom
  FROM t1;

おわりに

今回は、ST_Dumpを使ってマルチポリゴンを単一ポリゴンに変換しました。今回はマルチポリゴンのダンプでしたが、他のマルチ系ジオメトリでもダンプできます。ST_Dumpは、データをインポートした直後によく使いますので、覚えておいて損はありません。

注意すべき点として、ST_Dumpを含むクエリの結果では、ダンプしているカラム以外のカラムでは、元テーブルのタプルごとに値が同じになることが上げられます。ユニーク制限をかけているカラムで値が重複すると困ったことになるので、テーブル設計の段階で、これをアタマに入れておく必要があります。

また、ST_NumGeometriesを使って、マルチ系ジオメトリが持つ単一ジオメトリの数を見て、国土数値情報(行政区域)はマルチポリゴンとしてインポートされているけれども、実質的には単一ポリゴンであることを確認しました。

冒頭、「市区町村ごとにマルチポリゴンにした方が良い場合」があると書きましたが、今回はマルチポリゴンを作っていません。またの機会にでも紹介できれば良いかなと思っています。