Виберіть функції, які НЕ перетинаються в 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);

У мене був такий самий процес мислення, думав, що НЕ також зробить трюк, як і будь-який інший, коли умова
Luffydude

Відповіді:


41

Причина, з якою вона не працює з "не перетинається", полягає в тому, що ви порівнюєте лише геометрії в парах; буде однакова проблема і з нерозбірливістю. Кожна домашня точка буде роз'єднана деякими посилками, навіть якщо вона перетинає одну посилку.

Пропозиція 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 та отримати рядки там, де ідентифікатор посилки відсутній.

Тут необхідні індекси - це просторовий індекс та індекс на gid у посилках (якщо припустити, що id у таблиці посилок також називається gid).


2
Дуже дякую! Nicklas абсолютно правильно, що ST_Disjoint не дасть правильних результатів. ST_Disjoint повертає всі функції, тому що, як він зазначив, кожна точка розчленована деякими полігонами посилки в таблиці, в той час як цей фрагмент коду дав мені результати, на які я сподівався.
RyanDalton

Цей запит буде заплановано так само, як і цей gis.stackexchange.com/a/136177/6052, тож це питання, яке ви надаєте виключно стилю. =) Для тих, хто відповідає на покупки.
Еван Керролл

14

Можливо, ви шукаєте ST_Disjoint

ST_Disjoint - повертає ІСТИНА, якщо геометрії не "просторово перетинаються" - якщо вони не ділять простору разом.


2
Хоча ST_Disjoint робить це, проте він не використовує просторових індексів. Ви збираєтесь зачекати час
луооонг

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 EXISTSі 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

Як щодо ST_Disjoint? - Повертає ІСТИНА, якщо Геометрії не "просторово перетинаються" - якщо вони не ділять простору разом.


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 виконає трюк:

Це отримує всі адреси, які не знаходяться в околицях №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 - по-перше, багатокутників, пункти друге, яке відмінено від звичайного використання ST_Intersects.

Швидко і просто! Замислювались, як це правильно зробити на деякий час!


Також працював на "NOT ST_Within". Мій запит завершився за ~ 30,0 секунд як для NOT ST_Within, так і за допомогою зовнішнього з'єднання, а потім перевірка наявності Null на правій стороні, тому, здається, не буде досягнуто жодного результативного результату. Дякую!
Нейт Ваннер

@NateWanner корисно знати! Я не можу повірити, наскільки це легко і швидко !!!
DPSSpace

Це насправді дуже погана ідея, оскільки ви отримуєте декартовий продукт
Еван Керролл

@EvanCarroll що це означає?
DPSSpace

Це означає, що якщо ви не просто отримуєте 1 denver.address, ви отримуєте один за кожен невідповідний denver.neighborhood.
Еван Керролл

-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 є складним. ;)
Еван Керролл
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.