Seleziona le funzioni che NON si intersecano in PostGIS


41

Questa mi sembra una domanda così semplice (e probabilmente lo è) ma non riesco a trovare un esempio che mi dia la risposta. Usando PostGIS, voglio solo selezionare i punti che cadono al di fuori di poligoni. In definitiva, questo è l'inverso degli ST_Intersects, per quanto posso vederlo.

Esempio: ho un livello imposta e un livello punto indirizzo. Presumo che dovrei usare ST_Intersects, ma come faccio a dire di fare la selezione inversa? Ho pensato forse di aggiungere un'istruzione NOT davanti al codice qui sotto, ma non ha funzionato.

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

Ho avuto lo stesso processo di pensiero, ho pensato che il NOT avrebbe fatto anche il trucco come un altro dove la condizione
Luffydude,

Risposte:


41

Il motivo per cui non funziona con "non interseca" è che si confrontano solo le geometrie in coppie; ci sarà lo stesso problema con disgiunto. Ogni punto di casa disgiungerà alcuni pacchi anche se interseca un pacco.

il suggerimento di underdark non ha questo problema. C'è anche un altro trucco che probabilmente farà un uso più efficace degli indici:

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;

L'idea è di unirli a loro con st_intersects e ottenere le righe in cui l'id pacco non è presente.

Gli indici necessari qui sono un indice spaziale e un indice su gid nei pacchi (supponendo che id nella tabella dei pacchi sia anche chiamato gid).


2
Grazie mille! Nicklas ha esattamente ragione che ST_Disjoint non produrrà i risultati corretti. ST_Disjoint restituisce tutte le funzionalità perché, come ha sottolineato, ogni punto è disgiunto con alcuni poligoni di pacchi nella tabella, mentre questo frammento di codice mi ha dato i risultati sperati.
Ryan Dalton,

Questa query verrà pianificata allo stesso modo di questa gis.stackexchange.com/a/136177/6052, quindi è semplicemente una questione di stile che preferisci. =) Per quelle risposte allo shopping.
Evan Carroll,

14

Forse stai cercando ST_Disjoint

ST_Disjoint - Restituisce VERO se le Geometrie non si "intersecano spazialmente" - se non condividono alcuno spazio.


2
Mentre ST_Disjoint lo fa, tuttavia non utilizza indici spaziali. Stai andando ad aspettare un po 'di tempo
Nicks

9

Nel caso in cui non ci sia una funzione specializzata:

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

Qui usiamo NOT EXISTSe 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)
  );

3

Che ne dici di ST_Disjoint? - Restituisce VERO se le Geometrie non si "intersecano spazialmente" - se non condividono alcuno spazio.


4
whoops - è necessario fare un aggiornamento della pagina prima di rispondere :-)
Ian Turton

1

In alcuni casi è molto utile usare LATERAL JOIN, può essere molto veloce

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

Basta usare NOT prima che ST_Intersects faccia il trucco:

Questo ottiene tutti gli indirizzi che non si trovano nel quartiere # 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'

Nota l'ordine delle colonne geom: i poligoni prima, i punti in secondo luogo, che è invertito dal normale utilizzo di ST_Intersects.

Veloce e semplice! Mi sono chiesto come farlo correttamente per un po '!


Ha anche lavorato per "NOT ST_Within". La mia query è stata completata in ~ 30,0 secondi sia per NOT ST_Within sia usando un join esterno, controllando quindi Null sul lato destro, quindi non sembra esserci alcun impatto sulle prestazioni. Grazie!
Nate Wanner,

@NateWanner buono a sapersi! Non riesco a credere quanto sia facile e veloce !!!
DPSSpatial

Questa è in realtà una pessima idea perché stai ottenendo il prodotto cartesiano
Evan Carroll

@EvanCarroll cosa significa?
DPSSpatial

Significa che se non ricevi solo 1 denver.address, ne ricevi uno per ogni denver.neighbor non corrispondente.
Evan Carroll,

-1

Questa potrebbe non essere la soluzione più veloce ... Ma di solito imbroglio unendo tutte le funzionalità dell'altra tabella.

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

Bello e scattante se la tabella not_in_here non è così complessa.


Non è mai scattante. Non è così insicuro come sarebbe se not_in_here è complesso. ;)
Evan Carroll il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.