如何使此地理距离 SQL 查询与 Postgres 兼容

How can I make this geo-distance SQL query Postgres compatible

我尝试使用的一个库采用给定的纬度和经度,并计算 table 中的条目在距此一定距离内的 lat/lng。生成的 SQL 查询适用于 MySQL,但不适用于 PostgreSQL.

这是我的 server.log 文件中的条目,详细说明了 psql 给出的错误和完整的查询:

ERROR:  column "distance" does not exist at character 507
STATEMENT:  select *, ( '3959' * acos( cos( radians('53.49') ) * cos( radians( places.lat ) ) * cos( radians( places.lng ) - radians('-2.38') ) + sin( radians('53.49') ) * sin( radians( places.lat ) ) ) ) AS distance from (
                        Select *
                        From places
                        Where places.lat Between 53.475527714192 And 53.504472285808
                        And places.lng Between -2.4043246788967 And -2.3556753211033
                    ) As places where "places"."deleted_at" is null having "distance" <=  order by "distance" asc

知道 SQL 应该是什么后,我可以编辑生成它的 PHP 代码并将 PR 发送回图书馆。

查询使用 MySql 的特定语法。在 Postgres(以及我所知的所有其他 RDBMS)中,您应该使用派生的 table:

select *
from (
    select *, 
        (3959 * acos( cos( radians(53.49) ) * cos( radians( places.lat ) ) 
        * cos( radians( places.lng ) - radians(-2.38) ) 
        + sin( radians(53.49) ) * sin( radians( places.lat ) ) ) ) AS distance 
    from (
        select *
        from places
        where places.lat between 53.475527714192 and 53.504472285808
        and places.lng between -2.4043246788967 and -2.3556753211033
        ) as places 
    where places.deleted_at is null 
    ) sub
where distance <=  
order by distance asc

我还删除了数字常量的引号。

您的查询所做的是用长查询替换 postgresql 的 ST_Dwithin 函数。

ST_DWithin — Returns true if the geometries are within the specified distance of one another. For geometry units are in those of spatial reference and For geography units are in meters and measurement is defaulted to use_spheroid=true (measure around spheroid), for faster check, use_spheroid=false to measure along sphere.

很简单就去做

ST_DWithin(geometry1, geometry2)

其中geometry1和geometry2可以是点域(但也可以是其他几何数据类型二)

因此您的查询可能会变成

SELECT * FROM places WHERE
 ST_DWithin(ST_GeomFromText('POINT(-71.060316 48.432044)', 4326), places.geom) ORDER BY ST_Distance (ST_GeomFromText('POINT(-71.060316 48.432044)', 4326), places.geom)

您需要做的唯一更改是将纬度、经度放在一个 POINT 字段中。 (即使在 mysql 中,您也可能应该这样做)。您可以继续在单独的列中显示经纬度,但您将牺牲使用适当的地理类型可以获得的收益。

使用 ST_Dwithin 将比手动距离查询更快,因为它旨在利用 postgresql 上可以建立索引的几何列。

如果有一天你想回到 mysql 怎么办?那么 mysql 5.7 添加了 St_Dwithin 功能。