PostGIS Geometry Query仅对某些值返回“错误:对混合SRID几何进行操作”


17

我有两个带有SRID 4326定义的几何列的PostGIS表。我可以使用以下INSERT语句(其中lnglat以编程方式传递的值)毫无问题地插入表中:

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:

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,所以看来这不是正在发生的事情。)

Answers:


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(除非您为Mars或其他类似的椭球体想要其他SRID)。


至于为什么一个查询有错误,而另一个没有错误,则ST_Intersects首先进行&&边界框搜索,这是快速的,并且不关心SRID。如果边界框不相交,则不会出现任何混合SRID错误消息。但是,如果它们确实相交,则第二个过滤器是_ST_Intersects,它更精确,并检查两个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?每次明确设置它似乎很冗长。再次感谢!
jessykate

1
我已经更新了答案,建议使用geography类型,该类型始终为4326。此外,还有几种方法可以指定SRID。
Mike T

0

以下几点可能会有所帮助:一个Point(Double, Double)是您要强制转换为PostGIS数据类型的PostgreSQL本机函数。 ST_MakePoint(double x, double y)将创建适当的几何。另外,在您的问题中,您似乎将第二个参数称为经度。正确的顺序是x, y,对应于Longitude, Latitude。反转它们可以返回意外结果,而不会引发任何异常。

这些都不能真正解释为什么您的第一个示例有时会起作用,而其他示例却无法起作用,但是希望这将有助于您创建良好的查询。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.