PostGISジオメトリクエリは、特定の値に対してのみ「エラー:混合SRIDジオメトリの操作」を返します


17

SRID 4326で定義された2つのジオメトリ列を持つPostGISテーブルがあります。次の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)
);

また、geometry_columnsにSRIDのタイプが1つしかないことも確認しました。

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の別のジオメトリと使用する場合は、とが混在04326ます。空間参照が実際に異なる場合、これは通常便利なエラーです。ケースでは、SRIDは同じですが、SRIDをクエリポイントにエンコードしていません。そのため、クエリを修正するには、常にクエリポイントに同じSRIDを指定し、それらが混在することはなくなります。

補足説明として、このgeographyタイプのデフォルトのSRIDは4326(WGS 84)です(以下を参照)。

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

したがって、geographyタイプの代わりにgeometryタイプを使用する場合、SRIDを指定する必要はありません(火星などの代替楕円体に別のSRIDが必要な場合を除く)。


1つのクエリにエラーがあり、もう1つのクエリにエラーがない理由については、ST_Intersects最初に&&バウンディングボックス検索を行います。これは高速で、SRIDを気にしません。境界ボックスが交差しない場合、混合SRIDエラーメッセージは発生しません。しかし、それらが交差する場合、2番目のフィルターは_ST_Intersectsより正確で、2つの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を設定する方法はありますか?毎回明示的に設定するのはかなり冗長なようです。もう一度、ありがとう!
ジェシケー

1
答えを更新して、geography常に4326であるタイプの使用を提案しました。また、SRIDを指定する方法がいくつかあります。
マイクT

0

役立つ可能性のあるいくつかの観察:1つPoint(Double, Double)は、PostGISデータ型に強制しているネイティブPostgreSQL関数です。 ST_MakePoint(double x, double y)適切なジオメトリを作成します。また、あなたの質問では、2番目の引数を経度と呼んでいるようです。適切な順序はx, y、に対応しLongitude, Latitudeます。これらを逆にすると、例外をスローせずに予期しない結果を返す可能性があります。

最初の例がときどき機能し、他の例は機能しない理由を説明しているわけではありませんが、うまくいけば良いクエリを作成できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.