PostGIS Geometry Query devuelve "Error: operación en geometrías SRID mixtas" solo para ciertos valores

17

Tengo una tabla PostGIS con dos columnas de geometría, ambas definidas con SRID 4326. Puedo insertar en la tabla sin problemas, utilizando la siguiente INSERTinstrucción (donde lngy latson valores pasados ​​mediante programación):

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
)

Pero cuando busco una intersección usando ST_Intersects, dependiendo del valor del punto que obtengo ERROR: Operation on mixed SRID geometries.

Por ejemplo, esta consulta funciona:

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

Y esto se equivoca:

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

Tenga en cuenta que son consultas idénticas, excepto el valor de la longitud. He experimentado con diferentes valores, pero no identifiqué un punto de transición claro entre las consultas que funcionan y las que no.

Creo que fundamentalmente estoy malentendiendo algo. Por el momento, he resuelto / corregido / solucionado el problema volviendo a formatear la consulta para usarla ST_GeomFromTexty especificando explícitamente el SRID:

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

Pero honestamente, realmente no entiendo cuál es la diferencia, o si esta es realmente "la" solución.

Mi pregunta es: ¿Por qué recibo un error solo para valores específicos y cuál es la forma correcta de formatear esta consulta?

Aquí está mi definición de tabla para referencia:

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

También he verificado que solo hay un tipo de SRID en 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

Ayuda / consejos apreciados. ¡Gracias! (Nota: también he visto esta pregunta , pero dado que ya estoy definiendo explícitamente mis SRID de geometría al insertar en la tabla, parece que eso no es lo que está sucediendo).

jessykate
fuente

Respuestas:

24

Cuando especifica una geometría sin un SRID, en realidad es 0(o -1para la versión <2):

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

Entonces, cuando usa esta geometría con otra con SRID = 4326, se está mezclando 0y 4326. Esto suele ser un error útil si las referencias espaciales son realmente diferentes. Con su caso, los SRID son los mismos, pero no codificó el SRID en el punto de consulta. Por lo tanto, para corregir su consulta, siempre especifique el mismo SRID para su punto de consulta , y ya no se mezclarán.

Como nota al margen, el geographytipo tiene un SRID predeterminado de 4326 (WGS 84), como se muestra aquí:

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

Entonces, si usa geographytipos en lugar de geometrytipos, no es necesario especificar el SRID (a menos que desee un SRID diferente para un elipsoide alternativo para Marte o lo que sea).


En cuanto a por qué una consulta tiene un error y la otra no, ST_Intersectsprimero realiza una &&búsqueda en el cuadro delimitador, que es rápida y no le importan los SRID. No se generarán mensajes de error SRID mixtos si los cuadros delimitadores no se cruzan. Pero si se cruzan, el segundo filtro es _ST_Intersects, que es más preciso y verifica los dos SRID para asegurarse de que coinciden, y genera un error si se mezclan. Por ejemplo:

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

no tiene cuadros delimitadores que se crucen y no pasa por alto _ST_Intersects. Pero POINT(-122.334172173172 47.602634395263560)generará el error porque los cuadros delimitadores se superponen (aunque las geometrías en realidad no se cruzan).

Sin embargo, con las mismas geometrías y un filtro diferente:

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

arroja un error SRID mixto, porque no se consideran los cuadros delimitadores.

Mike T
fuente
Wow gracias. eso tiene sentido. ¿Es el prefijo de una consulta con SRID=4326(como lo hizo anteriormente) la forma correcta de establecer el SRID para el resto de la declaración? (en lugar de usar ST_GeomFromTextsimplemente porque no sabía cómo especificar el SRID ...?) ¿hay alguna forma de establecer un SRID predeterminado para las consultas? parece bastante detallado establecerlo explícitamente cada vez. ¡gracias otra véz!
jessykate
1
He actualizado mi respuesta para sugerir el uso de geographytipos, que siempre son 4326. Además, hay varias formas de especificar el SRID.
Mike T
0

Un par de observaciones que pueden ayudar: Una, Point(Double, Double)es una función nativa de PostgreSQL que está coaccionando a un tipo de datos PostGIS. ST_MakePoint(double x, double y)creará la geometría adecuada. Además, en su pregunta parece referirse al segundo argumento como longitud. El orden correcto es x, y, que corresponde a Longitude, Latitude. Hacer que se inviertan puede devolver resultados inesperados sin lanzar ninguna excepción.

Nada de esto explica realmente por qué su primer ejemplo funciona a veces y no a otros, pero espero que esto lo ayude a crear buenas consultas.

Scro
fuente