Pilih fitur yang TIDAK berpotongan di PostGIS

41

Bagi saya ini sepertinya pertanyaan sederhana (dan mungkin memang demikian) namun saya tidak dapat menemukan contoh yang memberi saya jawabannya. Menggunakan PostGIS, saya hanya ingin memilih titik yang berada di luar poligon. Pada akhirnya ini adalah kebalikan dari ST_Intersects, sejauh yang saya bisa melihatnya.

Contoh: Saya memiliki layer taxlot dan layer titik alamat. Saya berasumsi saya harus menggunakan ST_Intersects, tetapi bagaimana saya mengatakannya untuk melakukan seleksi terbalik? Saya pikir mungkin menambahkan pernyataan TIDAK di depan kode di bawah ini, tetapi itu tidak berhasil.

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);
Ryan Dalton
sumber
Saya memiliki proses pemikiran yang sama, berpikir bahwa TIDAK juga akan melakukan trik seperti kondisi lainnya
Luffydude

Jawaban:

41

Alasan tidak bekerja dengan "tidak berpotongan" adalah bahwa Anda hanya membandingkan geometri berpasangan; akan ada masalah yang sama dengan disjoint. Setiap housepoint akan memisahkan beberapa paket bahkan jika itu memotong satu paket.

saran underdark tidak memiliki masalah itu. Ada juga trik lain yang mungkin akan membuat penggunaan indeks lebih efektif:

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;

Idenya adalah untuk bergabung dengan mereka dengan st_intersects dan mendapatkan baris di mana id paket tidak ada.

Indeks yang diperlukan di sini adalah indeks spasial dan indeks pada gid dalam paket (dengan asumsi bahwa id dalam tabel paket disebut gid juga).

Nicklas Avén
sumber
2
Terima kasih banyak! Nicklas benar bahwa ST_Disjoint tidak akan menghasilkan hasil yang benar. ST_Disjoint mengembalikan semua fitur karena, seperti yang ia tunjukkan, setiap titik terputus dengan beberapa paket poligon di tabel, sementara potongan kode ini memberi saya hasil yang saya harapkan.
RyanDalton
Kueri ini akan direncanakan sama dengan yang ini gis.stackexchange.com/a/136177/6052 jadi ini murni masalah gaya yang Anda inginkan. =) Untuk jawaban belanja tersebut.
Evan Carroll
14

Anda mungkin mencari ST_Disjoint

ST_Disjoint - Mengembalikan BENAR jika Geometri tidak "berpotongan spasial" - jika mereka tidak berbagi ruang apa pun bersama-sama.

Jason Scheirer
sumber
2
Sementara ST_Disjoint melakukan itu, namun ia tidak menggunakan indeks spasial. Anda akan menunggu waktu loooooong
nickves
9

Dalam hal tidak ada fungsi khusus:

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
underdark
sumber
5

Di sini kami menggunakan NOT EXISTSdan CREATE 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)
  );
Carl Sena Afenu
sumber
3

Bagaimana dengan ST_Disjoint? - Mengembalikan BENAR jika Geometri tidak "berpotongan spasial" - jika mereka tidak berbagi ruang apa pun bersama-sama.

Ian Turton
sumber
4
whoops - perlu melakukan refresh halaman sebelum menjawab :-)
Ian Turton
1

Dalam beberapa kasus sangat berguna menggunakan LATERAL GABUNG, bisa sangat cepat Seharusnya terlihat seperti

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;
Jelen
sumber
1

Cukup gunakan TIDAK sebelum ST_Intersects melakukan trik:

Ini mendapatkan semua alamat yang tidak berada dalam lingkungan # 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'

Perhatikan urutan kolom geom - poligon pertama, poin kedua, yang dibalik dari penggunaan ST_Intersects yang biasa.

Cepat dan sederhana! Bertanya-tanya bagaimana melakukan ini dengan benar untuk sementara waktu!

DPSSpatial
sumber
Juga bekerja untuk "BUKAN ST_Within". Permintaan saya selesai dalam ~ 30,0 detik untuk NOT ST_Within dan menggunakan gabungan luar lalu memeriksa Null di sisi kanan, sehingga sepertinya tidak ada hit kinerja. Terima kasih!
Nate Wanner
@NateWanner senang tahu! Saya tidak percaya betapa mudah dan cepatnya itu !!!
DPSSpatial
Ini sebenarnya ide yang sangat buruk karena Anda mendapatkan produk cartesian
Evan Carroll
@ EvanCarroll apa artinya itu?
DPSSpatial
Itu berarti jika Anda tidak hanya mendapatkan 1 denver.address, Anda mendapatkan satu untuk setiap denver.nehall yang tidak cocok.
Evan Carroll
-1

Ini mungkin bukan solusi tercepat ... Tapi saya biasanya hanya menipu dengan menggabungkan semua fitur dari tabel lainnya.

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);

Bagus dan tajam jika tabel not_in_here tidak rumit.

Jamie Popkin
sumber
Itu tidak pernah tajam. Hanya saja tidak begitu tidak bahagia seperti jika not_in_here kompleks. ;)
Evan Carroll