Die PostGIS-Geometrieabfrage gibt nur für bestimmte Werte "Fehler: Vorgang mit gemischten SRID-Geometrien" zurück


17

Ich besitze eine PostGIS-Tabelle mit zwei Geometriespalten, die beide mit der SRID 4326 definiert wurden. Mit der folgenden INSERTAnweisung kann ich problemlos in die Tabelle einfügen (wobei lngund latwerden Werte programmgesteuert übergeben):

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
)

Aber wenn ich mit ST_Intersects nach einer Kreuzung frage, hängt das vom Wert des Punktes ab, den ich erhalte ERROR: Operation on mixed SRID geometries.

Diese Abfrage funktioniert beispielsweise wie folgt:

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

Und diese Fehler raus:

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

Beachten Sie, dass es sich mit Ausnahme des Längengrads um identische Abfragen handelt. Ich habe mit verschiedenen Werten experimentiert, aber keinen klaren Übergangspunkt zwischen den funktionierenden und den nicht funktionierenden Abfragen festgestellt.

Ich glaube, ich verstehe etwas grundlegend falsch. Im Moment habe ich das Problem gelöst / korrigiert / umgangen, indem ich die zu verwendende Abfrage neu formatiert ST_GeomFromTextund die SRID explizit angegeben habe:

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

Aber ich verstehe ehrlich gesagt nicht wirklich, was der Unterschied ist oder ob dies wirklich "die" Lösung ist.

Meine Frage lautet: Warum wird nur für bestimmte Werte ein Fehler angezeigt, und wie kann diese Abfrage ordnungsgemäß formatiert werden?

Hier ist meine Tabellendefinition als Referenz:

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

Ich habe auch überprüft, dass es nur einen Typ von SRID in den geometry_columns gibt:

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

Hilfe / Ratschläge erwünscht. Vielen Dank! (Hinweis: Ich habe diese Frage auch gesehen , aber da ich meine Geometrie-SRIDs bereits beim Einfügen in die Tabelle explizit definiere, scheint dies nicht der Fall zu sein.)

Antworten:


24

Wenn Sie eine Geometrie ohne SRID angeben, lautet diese tatsächlich 0(oder -1für Version <2):

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

Wenn Sie diese Geometrie also mit einer anderen Geometrie mit SRID = 4326 verwenden, mischt 0und 4326. Dies ist normalerweise ein nützlicher Fehler, wenn die räumlichen Verweise wirklich unterschiedlich sind. In Ihrem Fall sind die SRIDs identisch, aber Sie haben die SRID nicht für den Abfragepunkt codiert. Um Ihre Abfrage zu korrigieren, geben Sie immer dieselbe SRID für Ihren Abfragepunkt an , und sie werden nicht mehr gemischt.

Als Randnotiz hat der geographyTyp eine Standard-SRID von 4326 (WGS 84), wie hier gezeigt:

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

Wenn Sie also geographyTypen anstelle von geometryTypen verwenden, muss die SRID nicht angegeben werden (es sei denn, Sie möchten eine andere SRID für ein alternatives Ellipsoid für Mars oder was auch immer).


Die Frage, warum eine Abfrage einen Fehler aufweist und die andere keinen Fehler aufweist, führt ST_Intersectszunächst eine &&Begrenzungskastensuche durch, die schnell ist und sich nicht um SRIDs kümmert. Es werden keine gemischten SRID-Fehlermeldungen ausgegeben, wenn sich die Begrenzungsrahmen nicht schneiden. Wenn sie sich jedoch überschneiden, ist der zweite Filter _ST_Intersectsgenau und überprüft die beiden SRIDs, um sicherzustellen, dass sie übereinstimmen, und löst einen Fehler aus, wenn sie gemischt werden. Beispielsweise:

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

hat keine sich überschneidenden Begrenzungsrahmen und umgeht diese _ST_Intersects. Aber POINT(-122.334172173172 47.602634395263560)den Fehler erhöhen , weil die Begrenzungskästen überlappen sich (auch wenn die Geometrien nicht wirklich schneiden).

Mit den gleichen Geometrien und unterschiedlichen Filtern:

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

Löst einen gemischten SRID-Fehler aus, da Begrenzungsrahmen nicht berücksichtigt werden.


wow Danke. Das macht Sinn. Wird einer Abfrage SRID=4326(wie oben beschrieben) das richtige Präfix vorangestellt , um die SRID für den Rest der Anweisung festzulegen? (im Gegensatz zur Verwendung von ST_GeomFromTexteinfach, weil ich nicht wusste, wie ich die SRID angeben soll ...?) Gibt es eine Möglichkeit, eine Standard-SRID für Abfragen festzulegen? scheint ziemlich ausführlich zu sein, es jedes Mal explizit festzulegen. noch einmal Danke!
Jessykate

1
Ich habe meine Antwort aktualisiert, um die Verwendung von geographyTypen vorzuschlagen , die immer 4326 sind. Außerdem gibt es verschiedene Möglichkeiten , die SRID anzugeben.
Mike T

0

Einige Beobachtungen, die helfen können: Eine Point(Double, Double)ist eine native PostgreSQL-Funktion, die Sie für einen PostGIS-Datentyp verwenden. ST_MakePoint(double x, double y)erstellt die richtige Geometrie. Außerdem scheinen Sie in Ihrer Frage das zweite Argument als Längengrad zu bezeichnen. Die richtige Reihenfolge ist x, y, was entspricht Longitude, Latitude. Wenn diese umgekehrt werden, können unerwartete Ergebnisse zurückgegeben werden, ohne dass Ausnahmen auftreten.

Nichts davon erklärt wirklich, warum Ihr erstes Beispiel manchmal funktioniert und nicht andere, aber dies wird Ihnen hoffentlich dabei helfen, gute Abfragen zu erstellen.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.