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

如何使此地理距离SQL查询与Postgres兼容,sql,postgresql,postgis,Sql,Postgresql,Postgis,我尝试使用的一个库使用给定的纬度和经度,并使用表中的条目计算lat/lng与此保持一定距离。生成的SQL查询可用于MySQL,但不能用于PostgreSQL 下面是my server.log文件中的条目,详细说明了psql给出的错误和完整查询: ERROR: column "distance" does not exist at character 507 STATEMENT: select *, ( '3959' * acos( cos( radians('53.49') ) * cos(

我尝试使用的一个库使用给定的纬度和经度,并使用表中的条目计算lat/lng与此保持一定距离。生成的SQL查询可用于MySQL,但不能用于PostgreSQL

下面是my 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" <= $1 order by "distance" asc

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

查询使用MySql特有的语法。在Postgres和所有其他已知的RDBMS中,您应该使用派生表:

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 <= $1 
order by distance asc

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

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

ST_DWithin-如果几何图形在指定范围内,则返回true 彼此之间的距离。对于几何体,单位为空间单位 参考和地理单位为米,测量单位为米 默认使用_spheroid=true测量球体周围的距离,以便更快 选中,使用_spheroid=false沿球体进行测量

这很简单,只要做就行

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)
您需要做的唯一改变是将lat、lng合并到一个单点场中。即使在mysql中,您也应该这样做。你可以继续把你的lat,lng放在单独的列中,但你将牺牲你通过使用合适的地理类型所能获得的收益

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


如果有一天你想回到mysql呢?mysql 5.7添加了St_Dwithin特性

注意:“3959”是一个字符串常量。顺便说一句:请在查询中添加一些垂直空格。水平滚动不利于可读性…抱歉,这与server.log文件中的情况完全相同。是的,3959是一个常数,它的变化取决于距离是以英里还是公里为单位。虽然您接受的答案是将您的查询从mysql直译为postgresl,但这是次优的,并且没有利用postgresqlKlin的全部功能,因此无法给出正确的答案。但我想指出的是,syntaxis错误在哪里。因为postgres无法识别同一级别的别名,所以不能按距离的顺序选择值作为距离X。这就是为什么klin使用一个派生的table.btw,而不是计算cos radians53.49和sin radians53.49,为它们创建一次常量。在您的表格中添加cos弧度places.lng字段,这将大大加快您的计算速度。如果你有时间,试着检查分机。有几个地理函数将在将来帮助您。我想是的,我现在没有MySql来测试它。我在psql中遇到了这个错误:我只需要解决如何在第二个from中获取where null子句吗?很好,但我需要知道如何使用postgresql中使用上述查询连接两个表来获得结果。3959是公里还是英里?@shankarmsr-我认为您应该用一种更具体的方式将您的问题描述为一个新问题。错误:函数st_geomfromtextunknown,integer显然不存在,因为您没有启用Postgis扩展。下面是对函数的引用