A consulta de geometria PostGIS retorna "Erro: operação em geometrias SRID mistas" apenas para determinados valores

17

Eu tenho a tabela PostGIS com duas colunas de geometria, ambas definidas com SRID 4326. É possível inserir na tabela sem problemas, usando a seguinte INSERTinstrução (onde lnge latos valores são passados ​​programaticamente):

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
)

Mas quando eu procuro uma interseção usando ST_Intersects, dependendo do valor do ponto que recebo ERROR: Operation on mixed SRID geometries.

Por exemplo, esta consulta funciona:

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

E isso erros:

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

Observe que são consultas idênticas, exceto o valor da longitude. Eu experimentei valores diferentes, mas não identifiquei um ponto de transição claro entre as consultas que funcionam e não funcionam.

Eu acho que estou fundamentalmente mal entendendo alguma coisa. No momento, eu resolvi / corrigi / resolvi o problema re-formatando a consulta para usar ST_GeomFromTexte especificando explicitamente o SRID:

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

Mas sinceramente não entendo qual é a diferença ou se essa é realmente a "solução".

Minha pergunta é: Por que estou recebendo um erro apenas para valores específicos e qual é a maneira correta de formatar essa consulta?

Aqui está a minha definição de tabela para referência:

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

Também verifiquei que há apenas um tipo de SRID nas 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

Ajuda / conselhos apreciados. Obrigado! (Nota: Eu também vi essa pergunta , mas como já estou definindo explicitamente meus SRIDs de geometria ao inserir na tabela, parece que não é isso que está acontecendo.)

jessykate
fonte

Respostas:

24

Quando você especifica uma geometria sem um SRID, na verdade é 0(ou -1para a versão <2):

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

Então, quando você usa essa geometria com outra com SRID = 4326, ela está misturando 0e 4326. Geralmente, é um erro útil, se as referências espaciais forem realmente diferentes. No seu caso, os SRIDs são os mesmos, mas você não codificou o SRID no ponto de consulta. Portanto, para corrigir sua consulta, sempre especifique o mesmo SRID para o ponto de consulta e eles não serão mais misturados.

Como uma observação lateral, o geographytipo tem um SRID padrão de 4326 (WGS 84), como mostrado aqui:

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

Portanto, se você usar geographytipos em vez de geometrytipos, o SRID não precisará ser especificado (a menos que você queira um SRID diferente para um elipsóide alternativo para Marte ou o que for).


Quanto ao motivo pelo qual uma consulta tem um erro e a outra não, ST_Intersectsprimeiro faz uma &&pesquisa de caixa delimitadora, que é rápida e não se importa com SRIDs. Nenhuma mensagem de erro SRID mista será gerada se as caixas delimitadoras não se cruzarem. Mas se eles se cruzam, o segundo filtro é _ST_Intersects, que é mais preciso e verifica os dois SRIDs para garantir que eles correspondam, e gera um erro se eles forem misturados. Por exemplo:

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ão possui nenhuma caixa delimitadora e ignora _ST_Intersects. Mas POINT(-122.334172173172 47.602634395263560)aumentará o erro porque as caixas delimitadoras se sobrepõem (mesmo que as geometrias não se cruzem).

No entanto, com as mesmas geometrias e 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 
);

gera um erro SRID misto, porque as caixas delimitadoras não são consideradas.

Mike T
fonte
uau, obrigada. isso faz sentido. está prefixando uma consulta com SRID=4326(como você fez acima) a maneira correta de definir o SRID para o restante da instrução? (em vez de usar ST_GeomFromTextsimplesmente porque eu não sabia mais como especificar o SRID ...?) existe uma maneira de definir um SRID padrão para consultas? parece bastante detalhado defini-lo explicitamente cada vez. mais uma vez obrigado!
Jessykate
1
Atualizei minha resposta para sugerir o uso de geographytipos, que sempre são 4326. Além disso, existem várias maneiras de especificar o SRID.
Mike T
0

Algumas observações que podem ajudar: Uma, Point(Double, Double) é uma função nativa do PostgreSQL que você está usando para um tipo de dados PostGIS. ST_MakePoint(double x, double y)criará a geometria adequada. Além disso, na sua pergunta, você parece se referir ao segundo argumento como longitude. A ordem correta é a x, yque corresponde Longitude, Latitude. Revertê-los pode retornar resultados inesperados sem gerar exceções.

Nada disso realmente explica por que seu primeiro exemplo funciona algumas vezes e não outras, mas espero que isso ajude você a criar boas consultas.

Scro
fonte