PostGIS Geometry Query повертає "Помилка: Операція зі змішаною геометрією SRID" лише для певних значень


17

У мене PostGIS таблицю з двома колонками геометрії, як визначено з SRID 4326. Я можна вставити в таблицю без проблем, використовуючи наступне INSERTтвердження (де lngі latє значеннями , переданими в програмно):

INSERT INTO pad_meta (
    uuid, created, updated, name, origin, radius, area, expiry, creator
) VALUES (
    $1, now(), now(), $2, ST_GeomFromText('POINT(lng, lat)', 4326), $3, 
    ST_Buffer(ST_GeomFromText('POINT(lng, lat)', 4326), $4), $5, $6
)

Але коли я запитую перехрестя за допомогою ST_Intersects, залежно від значення точки, яку я отримую ERROR: Operation on mixed SRID geometries.

Наприклад, цей запит працює:

SELECT * FROM pad_meta where ST_Intersects(
    'POINT(-122.334172173172 46.602634395263560)'::geometry, area::geometry 
) ORDER BY created DESC;

І це помилки:

SELECT * FROM pad_meta where ST_Intersects(
    'POINT(-122.334172173172 47.602634395263560)'::geometry, area::geometry 
) ORDER BY created DESC;

Зауважте, вони є ідентичними запитами, за винятком значення довготи. Я експериментував з різними значеннями, але не визначив чіткої точки переходу між запитами, які працюють і не відповідають.

Я думаю, що я принципово щось не розумію. На даний момент я вирішив / виправив / вирішив проблему, переформатувавши запит для використанняST_GeomFromText та чітко вказавши SRID:

SELECT * FROM pad_meta where ST_Intersects(
    ST_GeomFromText('POINT(-122.334172173172 47.602634395263560)', 4326), area
) ORDER BY created DESC;

Але я, чесно кажучи, не дуже розумію, у чому різниця, чи це справді "" "рішення.

Моє запитання: Чому я отримую помилку лише для конкретних значень, і який правильний спосіб форматування цього запиту?

Ось моє визначення таблиці для довідок:

CREATE TABLE IF NOT EXISTS pad_meta (
  uuid CHAR(32),
  created TIMESTAMP,
  updated TIMESTAMP,
  name VARCHAR(128),
  origin GEOMETRY(Point, 4326),
  radius INTEGER,
  area GEOMETRY(Polygon, 4326),
  expiry TIMESTAMP,
  creator CHAR(32),
  PRIMARY KEY (uuid)
);

Я також переконався, що в геометричних стовпцях є лише один тип SRID:

SELECT f_table_name, f_geometry_column, srid FROM geometry_columns;
f_table_name | f_geometry_column | srid
--------------+-------------------+------
 pad_meta     | origin            | 4326
 pad_meta     | area              | 4326

Довідка / поради високо оцінені. Дякую! (Примітка. Я також бачив це питання , але оскільки я вже чітко визначаю свої геометричні SRID під час вставки в таблицю, схоже, що це не те, що відбувається.)

Відповіді:


24

Коли ви задаєте геометрію без SRID, це насправді 0(або -1для версії <2):

SELECT ST_SRID('POINT(-122.334172173172 46.602634395263560)'::geometry);
 st_srid
---------
       0

Отже, коли ви використовуєте цю геометрію з іншою з SRID = 4326, вона змішується 0і 4326. Зазвичай це корисна помилка, якщо просторові посилання справді різні. У вашому випадку SRID-адреси однакові, але ви не кодували SRID до точки запиту. Отже, для виправлення запиту завжди вказуйте однаковий SRID для точки запиту , і вони більше не будуть змішуватися.

В якості примітки, тип має SRID за замовчуванням 4326 (WGS 84), як показано тут:geography

SELECT ST_SRID('POINT(-122.334172173172 46.602634395263560)'::geography::geometry);
 st_srid
---------
    4326

Отже, якщо ви використовуєте geographyтипи замість geometryтипів, SRID не потрібно вказувати (якщо тільки ви не хочете іншого SRID для альтернативного еліпсоїда для Марса чи іншого).


Щодо того, чому один запит має помилку, а другий - ні, ST_Intersectsспочатку &&виконується пошук обмежувального вікна, який є швидким, і не хвилює SRID. Жодні змішані повідомлення про помилки SRID не будуть підніматися, якщо обмежувальні поля не перетинаються. Але якщо вони перетинаються, другий фільтр є _ST_Intersectsбільш точним і перевіряє два SRID, щоб переконатися, що вони збігаються, і створює помилку, якщо вони змішуються. Наприклад:

WITH pad_meta AS (
    SELECT 'SRID=4326;POLYGON((-124 50, -124 47, -121 50, -124 50))'::geometry AS area)

SELECT * FROM pad_meta where ST_Intersects(
    'POINT(-122.334172173172 46.602634395263560)'::geometry, area::geometry 
);

не має жодних пересічних обмежувальних коробок та байпасів _ST_Intersects. АлеPOINT(-122.334172173172 47.602634395263560) помилка призведе до того, що обмежувальні коробки перекриваються (навіть якщо геометрії насправді не перетинаються).

Однак з однаковими геометріями та різними фільтрами:

WITH pad_meta AS (
    SELECT 'SRID=4326;POLYGON((-124 50, -124 47, -121 50, -124 50))'::geometry AS area)

SELECT * FROM pad_meta where _ST_Intersects(
    'POINT(-122.334172173172 46.602634395263560)'::geometry, area::geometry 
);

видає змішану помилку SRID, оскільки обмежувальні поля не враховуються.


вау, дякую що має сенс. є префіксація запиту SRID=4326(як ви це робили вище) правильним способом встановити SRID для решти оператора? (на відміну від використання ST_GeomFromTextпросто тому, що я не знав, як інакше вказати SRID ...?) чи існує спосіб встановити SRID за замовчуванням для запитів? видається досить багатослівним, щоб кожного разу чітко його встановлювати. ще раз дякую!
jessykate

1
Я оновив свою відповідь, щоб запропонувати використовувати geographyтипи, які завжди є 4326. Також існує декілька способів вказати SRID.
Майк Т

0

Кілька спостережень, які можуть допомогти: Перше Point(Double, Double)- це нативна функція PostgreSQL, яку ви примушуєте до типу даних PostGIS. ST_MakePoint(double x, double y)створить належну геометрію. Крім того, у вашому запитанні ви, здається, посилаєтесь на другий аргумент як довготу. Правильний порядок є x, y, що відповідає Longitude, Latitude. Повернення цих змін може повернути несподівані результати без викидів.

Ніщо з цього насправді не пояснює, чому ваш перший приклад працює іноді, а не інші, але, сподіваємось, це допоможе вам створити хороші запити.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.