PostGIS Geometry Query renvoie «Erreur: opération sur des géométries SRID mixtes» uniquement pour certaines valeurs

17

J'ai une table PostGIS avec deux colonnes de géométrie, toutes deux définies avec SRID 4326. Je peux insérer dans la table sans problème, en utilisant l' INSERTinstruction suivante (où lnget latsont les valeurs transmises par programme):

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
)

Mais quand je demande une intersection en utilisant ST_Intersects, selon la valeur du point que j'obtiens ERROR: Operation on mixed SRID geometries.

Par exemple, cette requête fonctionne:

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

Et cela se trompe:

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

Notez que ce sont des requêtes identiques à l'exception de la valeur de la longitude. J'ai expérimenté différentes valeurs, mais je n'ai pas identifié de point de transition clair entre les requêtes qui fonctionnent et ne fonctionnent pas.

Je pense que je comprends fondamentalement quelque chose. Pour le moment, j'ai résolu / corrigé / contourné le problème en reformatant la requête à utiliser ST_GeomFromTextet en spécifiant explicitement le SRID:

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

Mais honnêtement, je ne comprends pas vraiment quelle est la différence, ou si c'est vraiment "la" solution.

Ma question est: pourquoi est-ce que j'obtiens une erreur uniquement pour des valeurs spécifiques, et quelle est la bonne façon de formater cette requête?

Voici ma définition de table pour référence:

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

J'ai également vérifié qu'il n'y a qu'un seul type de SRID dans les 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

Aide / conseils appréciés. Je vous remercie! (Remarque: j'ai également vu cette question , mais comme je définis déjà explicitement mes SRID de géométrie lors de l'insertion dans la table, il semble que ce n'est pas ce qui se passe.)

jessykate
la source

Réponses:

24

Lorsque vous spécifiez une géométrie sans SRID, c'est en fait 0(ou -1pour la version <2):

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

Donc, lorsque vous utilisez cette géométrie avec une autre avec SRID = 4326, elle mélange 0et 4326. C'est généralement une erreur utile, si les références spatiales sont vraiment différentes. Avec votre cas, les SRID sont les mêmes, mais vous n'avez pas codé le SRID au point de requête. Ainsi, pour corriger votre requête, spécifiez toujours le même SRID pour votre point de requête , et ils ne seront plus mélangés.

En remarque, le geographytype a un SRID par défaut de 4326 (WGS 84), comme indiqué ici:

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

Donc, si vous utilisez des geographytypes au lieu de geometrytypes, le SRID n'a pas besoin d'être spécifié (sauf si vous voulez un SRID différent pour un autre ellipsoïde pour Mars ou autre).


Quant à savoir pourquoi une requête a une erreur, et l'autre pas, fait d' ST_Intersectsabord une &&recherche de zone de délimitation, qui est rapide et ne se soucie pas des SRID. Aucun message d'erreur SRID mixte ne sera généré si les boîtes englobantes ne se croisent pas. Mais s'ils se croisent, le deuxième filtre est _ST_Intersects, qui est plus précis et vérifie les deux SRID pour s'assurer qu'ils correspondent, et déclenche une erreur s'ils sont mélangés. Par exemple:

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

n'a pas de boîtes englobantes qui se croisent et contourne _ST_Intersects. Mais POINT(-122.334172173172 47.602634395263560)cela soulèvera l'erreur car les boîtes englobantes se chevauchent (même si les géométries ne se coupent pas réellement).

Cependant, avec les mêmes géométries et différents filtres:

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

renvoie une erreur SRID mixte, car les zones de délimitation ne sont pas prises en compte.

Mike T
la source
Wow merci. ça a du sens. préfixe une requête avec SRID=4326(comme vous l'avez fait ci-dessus) la bonne façon de définir le SRID pour le reste de l'instruction? (par opposition à l'utilisation ST_GeomFromTextsimplement parce que je ne savais pas comment spécifier le SRID ...?) existe-t-il un moyen de définir un SRID par défaut pour les requêtes? semble assez verbeux pour le définir explicitement à chaque fois. Merci encore!
jessykate
1
J'ai mis à jour ma réponse pour suggérer d'utiliser des geographytypes, qui sont toujours 4326. En outre, il existe plusieurs façons de spécifier le SRID.
Mike T
0

Quelques observations qui peuvent vous aider: Premièrement, il Point(Double, Double)s'agit d'une fonction PostgreSQL native que vous contraignez à un type de données PostGIS. ST_MakePoint(double x, double y)créera une géométrie appropriée. De plus, dans votre question, vous semblez faire référence au deuxième argument en tant que longitude. L'ordre correct est x, y, ce qui correspond à Longitude, Latitude. Les inverser peut renvoyer des résultats inattendus sans lever d'exceptions.

Rien de tout cela n'explique vraiment pourquoi votre premier exemple fonctionne parfois et pas d'autres, mais j'espère que cela vous aidera à créer de bonnes requêtes.

Scro
la source