PostGISで交差しないフィーチャを選択します


41

これは私にはそのような単純な質問のように思えます(おそらくそうです)が、答えを与える例を見つけることができないようです。PostGISを使用して、ポリゴンの外側にあるポイントを選択したいだけです。最終的に、これはST_Intersectsの逆であり、私が見る限りです。

例:タックスロットレイヤーと住所ポイントレイヤーがあります。ST_Intersectsを使用する必要があると思いますが、逆選択を行うようにするにはどうすればよいですか?次のコードの前にNOTステートメントを追加することも考えられましたが、うまくいきませんでした。

CREATE table t_intersect AS
SELECT 
  hp.gid, 
  hp.st_address, 
  hp.city, 
  hp.st_num,
  hp.the_geom
FROM 
  public.parcel as par,
  public.housepoints as hp
WHERE 
  ST_Intersects(hp.the_geom,par.the_geom);

私は同じ思考プロセスを持っていて、NOTは他のwhere条件のようなトリックを行うだろうと考えていました
ルフィデュード

回答:


41

「交差しない」では機能しないのは、ジオメトリをペアでしか比較しないためです。ばらばらの場合も同じ問題が発生します。すべてのハウスポイントは、1つのパーセルと交差する場合でも、いくつかのパーセルを分離します。

underdarkの提案にはその問題はありません。おそらくインデックスをより効果的に使用する別のトリックもあります。

CREATE TABLE t_intersect AS
SELECT 
  hp.gid, 
  hp.st_address, 
  hp.city, 
  hp.st_num,
  hp.the_geom
FROM 
  public.housepoints AS hp LEFT JOIN
  public.parcel AS par ON
  ST_Intersects(hp.the_geom,par.the_geom)
WHERE par.gid IS NULL;

考えは、st_intersectsでそれらを結合し、パーセルIDが存在しない行を取得することです。

ここで必要なインデックスは、空間インデックスとパーセル内のgidのインデックスです(パーセルテーブル内のidもgidと呼ばれます)。


2
どうもありがとうございました!Nicklasは、ST_Disjointが正しい結果を生成しないことを正確に理解しています。ST_Disjointはすべてのフィーチャを返します。彼が指摘したように、各ポイントはテーブル内のいくつかのパーセルポリゴンと切り離されているため、このコードスニペットは私が期待していた結果をもたらしました。
RyanDalton

このクエリは、このgis.stackexchange.com/a/136177/6052と同じように計画されるため、純粋にスタイルの問題です。=)これらの買い物の答え。
エヴァンキャロル

14

あなたはST_Disjointを探しているかもしれません

ST_Disjoint —ジオメトリが「空間的に交差しない」場合、つまり空間を共有していない場合、TRUEを返します。


2
ST_Disjointはそれを行いますが、空間インデックスは使用しません。あなたはloooooong時間を待つつもりです
ニックス

9

特別な機能がない場合:

CREATE table t_intersect AS
SELECT 
  hp.gid, 
  hp.st_address, 
  hp.city, 
  hp.st_num,
  hp.the_geom
FROM
  public.housepoints as hp
WHERE
  hp.gid NOT IN 
  (
    SELECT 
      h.gid
    FROM 
      public.parcel as p,
      public.housepoints as h
    WHERE 
      ST_Intersects(h.the_geom,p.the_geom)
  ) AS foo

5

ここではNOT EXISTSCREATE TABLE AS SELECT(CTAS)を使用します

CREATE table t_intersect
AS
  SELECT 
    hp.gid,
    hp.st_address,
    hp.city, hp.st_num,
    hp.the_geom
  FROM public.housepoints AS hp
  WHERE NOT EXISTS (
    SELECT 1
    FROM public.parcel AS par 
    WHERE ST_Intersects(hp.the_geom,par.the_geom)
  );

3

ST_Disjointはどうですか?—ジオメトリが「空間的に交差」していない場合-ジオメトリがスペースを共有していない場合、TRUEを返します。


4
おっと-答える前にページを更新する必要があります:-)
イアンタートン

1

場合によってはLATERAL JOINを使用すると非常に便利です。非常に高速になります。

SELECT * FROM houses h
LEFT JOIN LATERAL (
   SELECT True t FROM parcels p
   WHERE ST_Intersects(p.geom, h.geom)
   LIMIT 1
) p ON True
WHERE p.t IS NULL;

1

ST_Intersectsの前にNOTを使用するだけで、トリックが実行されます。

これは、近隣#62内にないすべてのアドレスを取得します。

select 
a.*
from denver.neighborhoods as n
join denver.addresses as a on not ST_Intersects(n.geom, a.geom)
where n.nbhd_id = '62'

geom列の順序に注意してください-最初にポリゴン、2番目にポイント、ST_Intersectsの通常の使用とは逆です。

早くて簡単!しばらくこれを正しく行う方法を疑問に思っていました!


「NOT ST_Within」でも働いていました。私のクエリは、NOT ST_Withinと外部結合の使用の両方で約30.0秒で完了し、右側でNullをチェックしているため、パフォーマンスに影響はないようです。ありがとう!
ネイトワナー

@NateWanner知って良かった!私はそれがどれほど簡単で速いか信じられません!!!
-DPSSpatial

デカルト積を取得しているため、これは実際にはかなり悪い考えです
エヴァンキャロル

@EvanCarrollそれはどういう意味ですか?
DPSS空間

つまり、denver.addressを1つだけ取得していない場合は、一致しないdenver.neighborhoodごとに1つを取得しています。
エヴァンキャロル

-1

これは最速の解決策ではないかもしれません...しかし、私は通常、他のテーブルのすべての機能を結合することでごまかします。

Create table blah as
select
  d.*
from
  data_i_want d,
  (select st_union(geom) geom from not_in_here) n
where
  st_disjoint(d.geom,n.geom);

not_in_hereテーブルがそれほど複雑でない場合は、素晴らしくてきぱきとします。


それは決してきびきびしない。not_in_hereが複雑な場合ほど簡単ではありません。;)
エヴァンキャロル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.