PostGIS Geometry Query mengembalikan "Kesalahan: Operasi pada geometri SRID campuran" hanya untuk nilai-nilai tertentu

17

Saya memiliki tabel PostGIS dengan dua kolom geometri, keduanya didefinisikan dengan SRID 4326. Saya dapat menyisipkan ke dalam tabel tanpa masalah, menggunakan INSERTpernyataan berikut (di mana lngdan latnilai-nilai diteruskan secara terprogram):

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
)

Tetapi ketika saya meminta persimpangan dengan menggunakan ST_Intersects, tergantung pada nilai titik yang saya dapatkan ERROR: Operation on mixed SRID geometries.

Misalnya, kueri ini berfungsi:

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

Dan ini salah:

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

Catatan, mereka adalah query yang identik kecuali nilai bujur. Saya telah bereksperimen dengan nilai yang berbeda, tetapi tidak mengidentifikasi titik transisi yang jelas antara kueri yang berfungsi dan tidak.

Saya pikir saya pada dasarnya salah paham tentang sesuatu. Untuk saat ini, saya telah memecahkan / memperbaiki / mengatasi masalah dengan memformat ulang kueri untuk digunakan ST_GeomFromTextdan secara spesifik menentukan SRID:

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

Tapi sejujurnya saya tidak begitu mengerti apa perbedaannya, atau apakah ini benar-benar solusi.

Pertanyaan saya adalah: Mengapa saya mendapatkan kesalahan hanya untuk nilai tertentu, dan apa cara yang tepat untuk memformat kueri ini?

Berikut ini adalah definisi tabel saya untuk referensi:

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

Saya juga telah memverifikasi bahwa hanya ada satu jenis SRID di 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

Bantuan / saran dihargai. Terima kasih! (Catatan: Saya juga telah melihat pertanyaan ini , tetapi karena saya sudah secara eksplisit mendefinisikan SRID geometri saya ketika memasukkan ke dalam tabel, sepertinya bukan itu yang terjadi.)

jessykate
sumber

Jawaban:

24

Saat Anda menentukan geometri tanpa SRID, sebenarnya 0(atau -1untuk versi <2):

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

Jadi ketika Anda menggunakan geometri ini dengan yang lain dengan SRID = 4326, itu adalah pencampuran 0dan 4326. Ini biasanya kesalahan bermanfaat, jika referensi spasial benar-benar berbeda. Dengan kasing Anda, SRID sama, tetapi Anda tidak menyandikan SRID ke titik kueri. Jadi, untuk memperbaiki kueri Anda selalu tentukan SRID yang sama untuk titik kueri Anda , dan mereka tidak akan lagi dicampur.

Sebagai catatan, ini geographyjenis memiliki SRID default 4326 (WGS 84), seperti yang ditunjukkan di sini:

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

Jadi, jika Anda menggunakan geographytipe sebagai ganti geometrytipe, SRID tidak perlu ditentukan (kecuali jika Anda menginginkan SRID berbeda untuk ellipsoid alternatif untuk Mars atau apa pun).


Mengapa satu kueri memiliki kesalahan, dan yang lainnya tidak, ST_Intersectspertama melakukan &&pencarian kotak pembatas, yang cepat, dan tidak peduli tentang SRID. Tidak ada pesan kesalahan SRID campuran yang dimunculkan jika kotak pembatas tidak berpotongan. Tetapi jika mereka berpotongan, filter kedua adalah _ST_Intersects, yang lebih tepat dan memeriksa dua SRID untuk memastikan mereka cocok, dan memunculkan kesalahan jika mereka dicampur. Sebagai contoh:

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

tidak memiliki kotak pembatas yang memotong, dan memotong _ST_Intersects. Tetapi POINT(-122.334172173172 47.602634395263560)akan meningkatkan kesalahan karena kotak berlari tumpang tindih (meskipun geometri tidak benar-benar berpotongan).

Namun, dengan geometri dan filter yang berbeda:

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

melempar kesalahan SRID campuran, karena kotak pembatas tidak dipertimbangkan.

Mike T
sumber
Wow Terimakasih. itu masuk akal. adalah awalan kueri dengan SRID=4326(seperti yang Anda lakukan di atas) cara yang tepat untuk mengatur SRID untuk sisa pernyataan? (sebagai lawan menggunakan ST_GeomFromTexthanya karena saya tidak tahu bagaimana lagi menentukan SRID ...?) apakah ada cara untuk menetapkan SRID default untuk permintaan? Tampaknya agak verbose untuk secara eksplisit mengaturnya setiap kali. sekali lagi terima kasih!
jessykate
1
Saya telah memperbarui jawaban saya untuk menyarankan menggunakan geographytipe, yang selalu 4326. Juga, ada beberapa cara untuk menentukan SRID.
Mike T
0

Beberapa pengamatan yang dapat membantu: Satu, Point(Double, Double)adalah fungsi asli PostgreSQL yang Anda paksakan untuk tipe data PostGIS. ST_MakePoint(double x, double y)akan membuat geometri yang tepat. Juga, dalam pertanyaan Anda, Anda sepertinya merujuk pada argumen kedua sebagai bujur. Urutan yang tepat adalah x, y, yang sesuai dengan Longitude, Latitude. Membalikkannya dapat mengembalikan hasil yang tidak terduga tanpa membuang pengecualian.

Tidak satu pun dari ini yang benar-benar menjelaskan mengapa contoh pertama Anda kadang-kadang berfungsi dan bukan yang lain, tetapi mudah-mudahan ini akan membantu Anda membuat kueri yang bagus.

Scro
sumber