Wybierz funkcje, które NIE przecinają się w PostGIS

41

Wydaje mi się, że to takie proste pytanie (i prawdopodobnie tak jest), ale nie mogę znaleźć przykładu, który dałby mi odpowiedź. Korzystając z PostGIS, chcę po prostu wybrać punkty, które wypadają poza wielokątami. Ostatecznie jest to odwrotność ST_Intersects, o ile widzę.

Przykład: Mam warstwę taksówki i warstwę adresu. Zakładam, że powinienem używać ST_Intersects, ale jak mam to zrobić, aby dokonać wyboru wstecznego? Pomyślałem, że może dodanie instrukcji NOT przed kodem poniżej, ale to nie zadziałało.

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);
RyanDalton
źródło
Miałem ten sam proces myślowy, myślałem, że NIE wykona również
lewy

Odpowiedzi:

41

Powodem, dla którego nie działa z „nie przecina się”, jest to, że porównujesz geometrie tylko parami; będzie ten sam problem z rozłącznością. Każdy punkt domu rozłącza niektóre działki, nawet jeśli przecina jedną działkę.

sugestia podmroku nie ma tego problemu. Jest też inna sztuczka, która prawdopodobnie pozwoli na bardziej efektywne wykorzystanie indeksów:

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;

Chodzi o to, aby połączyć je za pomocą st_intersects i uzyskać wiersze, w których identyfikator paczki nie jest obecny.

Potrzebne tutaj indeksy to indeks przestrzenny i indeks gid w paczkach (przy założeniu, że tabela id w paczkach jest również nazywana gid).

Nicklas Avén
źródło
2
Dziękuję Ci bardzo! Nicklas ma dokładnie rację, że ST_Disjoint nie da poprawnych wyników. ST_Disjoint zwraca wszystkie funkcje, ponieważ, jak wskazał, każdy punkt jest rozłączony z pewnymi wielokątami działki w tabeli, podczas gdy ten fragment kodu dał mi wyniki, na które liczyłem.
RyanDalton,
To zapytanie zostanie zaplanowane tak samo jak to gis.stackexchange.com/a/136177/6052, więc jest to wyłącznie kwestia stylu, który preferujesz. =) Dla tych odpowiedzi na zakupy.
Evan Carroll
14

Być może szukasz ST_Disjoint

ST_Disjoint - Zwraca wartość PRAWDA, jeśli geometrie nie „przecinają się przestrzennie” - jeśli nie dzielą ze sobą żadnej przestrzeni.

Jason Scheirer
źródło
2
Chociaż ST_Disjoint to robi, nie wykorzystuje jednak indeksów przestrzennych. Będziesz musiał długo czekać
nickves
9

W przypadku braku specjalistycznej funkcji:

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
podmrok
źródło
5

Tutaj używamy NOT EXISTSi 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
źródło
3

Co powiesz na ST_Disjoint? - Zwraca wartość PRAWDA, jeśli geometrie nie „przecinają się przestrzennie” - jeśli nie dzielą ze sobą żadnej przestrzeni.

Ian Turton
źródło
4
ups - musisz odświeżyć stronę przed odpowiedzią :-)
Ian Turton
1

W niektórych przypadkach bardzo przydatne jest użycie POŁĄCZENIA PÓŹNIEJ, może być bardzo szybkie. Powinno to wyglądać

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
źródło
1

Po prostu użycie NOT zanim ST_Intersects załatwi sprawę:

Otrzymuje to wszystkie adresy, które nie znajdują się w sąsiedztwie # 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'

Zwróć uwagę na kolejność kolumn geom - najpierw wielokąty, punkty drugie, co jest odwrócone od zwykłego użycia ST_Intersects.

Szybki i prosty! Od jakiegoś czasu zastanawiam się, jak to zrobić poprawnie!

DPSSpatial
źródło
Pracował również dla „NOT ST_Within”. Moje zapytanie zakończyło się w ~ 30,0 sekund zarówno dla NOT ST_Within, jak i przy użyciu zewnętrznego sprzężenia, a następnie sprawdziłem, czy po prawej stronie nie ma wartości Null, więc wydaje się, że nie ma żadnego spadku wydajności. Dzięki!
Nate Wanner
@NateWanner dobrze wiedzieć! Nie mogę uwierzyć, jakie to łatwe i szybkie !!!
DPSSpatial
To naprawdę zły pomysł, ponieważ dostajesz kartezjański produkt
Evan Carroll
@EvanCarroll co to znaczy?
DPSSpatial
Oznacza to, że jeśli nie dostajesz tylko 1 adresu denver.adres, dostajesz jeden za każde niepasujące sąsiedztwo denver.reater.
Evan Carroll
-1

To może nie być najszybsze rozwiązanie ... Ale zwykle oszukuję, łącząc wszystkie funkcje drugiego stołu.

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

Ładne i szybkie, jeśli tabela not_in_here nie jest tak złożona.

Jamie Popkin
źródło
To nigdy nie jest fajne. To nie tylko jako unsnappy jak byłoby, gdyby not_in_here jest złożona. ;)
Evan Carroll