Zapytanie Geometria PostGIS zwraca „Błąd: Operacja na mieszanych geometriach SRID” tylko dla niektórych wartości

17

Mam tabelę PostGIS z dwiema kolumnami geometrii, obie zdefiniowane za pomocą SRID 4326. Mogę bez problemu wstawiać do tabeli, używając następującej INSERTinstrukcji (gdzie lngi gdzie latwartości są przekazywane programowo):

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
)

Ale kiedy pytam o skrzyżowanie za pomocą ST_Intersects, w zależności od wartości punktu, który otrzymuję ERROR: Operation on mixed SRID geometries.

Na przykład to zapytanie działa:

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

A to błędy:

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

Uwaga: są to identyczne zapytania, z wyjątkiem wartości długości geograficznej. Eksperymentowałem z różnymi wartościami, ale nie zidentyfikowałem wyraźnego punktu przejścia między zapytaniami, które działają i nie działają.

Myślę, że zasadniczo coś nie rozumiem. Na razie rozwiązałem / poprawiłem / ST_GeomFromTextobejrzałem ten problem, ponownie formatując zapytanie, aby użyć i jawnie określając SRID:

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

Ale szczerze mówiąc, tak naprawdę nie rozumiem, na czym polega różnica lub czy to naprawdę „rozwiązanie”.

Moje pytanie brzmi: dlaczego pojawia się błąd tylko w przypadku określonych wartości i jaki jest właściwy sposób sformatowania tego zapytania?

Oto definicja mojej tabeli w celach informacyjnych:

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

Zweryfikowałem również, że istnieje tylko jeden typ SRID w geometry_columns:

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

Doceniona pomoc / porady. Dziękuję Ci! (Uwaga: widziałem również to pytanie , ale ponieważ już jawnie definiuję moje geometryczne identyfikatory SRID podczas wstawiania do tabeli, wygląda na to, że tak się nie dzieje.)

jessykate
źródło

Odpowiedzi:

24

Gdy określisz geometrię bez identyfikatora SRID, będzie to faktycznie 0(lub -1dla wersji <2):

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

Więc kiedy użyjesz tej geometrii z inną z SRID = 4326, to będzie mieszanie 0i 4326. Jest to zwykle przydatny błąd, jeśli odniesienia przestrzenne są naprawdę różne. W twoim przypadku identyfikatory SRID są takie same, ale nie zakodowałeś identyfikatora SRID w punkcie zapytania. Tak więc, aby naprawić zapytanie, zawsze określ ten sam SRID dla punktu zapytania i nie będą już mieszane.

Na marginesie, typ ma domyślny SRID z 4326 (WGS 84), jak pokazano poniżej:geography

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

Zatem jeśli użyjesz geographytypów zamiast geometrytypów, SRID nie musi być określony (chyba że chcesz innego SRID dla alternatywnej elipsoidy dla Marsa lub cokolwiek innego).


Jeśli chodzi o to, dlaczego jedno zapytanie zawiera błąd, a drugie nie, ST_Intersectsnajpierw wykonuje &&wyszukiwanie pola granicznego, które jest szybkie i nie przejmuje się identyfikatorami SRID. Mieszane komunikaty o błędach SRID nie będą wywoływane, jeśli obwiednie nie przecinają się. Ale jeśli się przecinają, drugi filtr jest _ST_Intersectsdokładniejszy i sprawdza dwa identyfikatory SRID, aby upewnić się, że pasują, i powoduje błąd, jeśli są pomieszane. Na przykład:

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

nie ma żadnych przecinających się obwiedni i pomija _ST_Intersects. Ale POINT(-122.334172173172 47.602634395263560)podniesie błąd, ponieważ ramki ograniczające nakładają się na siebie (nawet jeśli geometria tak naprawdę się nie przecina).

Jednak z tą samą geometrią i innym filtrem:

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

zgłasza mieszany błąd SRID, ponieważ ramki ograniczające nie są uwzględniane.

Mike T.
źródło
wow, dziękuję to ma sens. czy przedrostek zapytania SRID=4326(tak jak to zrobiłeś powyżej) to właściwy sposób ustawienia SRID dla reszty instrukcji? (w przeciwieństwie do używania ST_GeomFromTextpo prostu dlatego, że nie wiedziałem, jak inaczej określić SRID ...?) Czy istnieje sposób, aby ustawić domyślny SRID dla zapytań? Wydaje się, że za każdym razem jest to jawne. jeszcze raz dzięki!
jessykate
1
Zaktualizowałem moją odpowiedź, aby zasugerować użycie geographytypów, które zawsze wynoszą 4326. Ponadto istnieje kilka sposobów określania SRID.
Mike T
0

Kilka uwag, które mogą pomóc: Po pierwsze, Point(Double, Double)jest natywną funkcją PostgreSQL, którą wymuszasz na typ danych PostGIS. ST_MakePoint(double x, double y)stworzy odpowiednią geometrię. Ponadto w swoim pytaniu wydajesz się odnosić do drugiego argumentu jako długości geograficznej. Właściwa kolejność to x, y, co odpowiada Longitude, Latitude. Odwrócenie tych ustawień może zwrócić nieoczekiwane wyniki bez zgłaszania wyjątków.

Nic z tego tak naprawdę nie wyjaśnia, dlaczego twój pierwszy przykład czasami działa, a nie inne, ale mam nadzieję, że pomoże to w tworzeniu dobrych zapytań.

Scro
źródło