使用带有PostgreSQL和PDO的Haversine公式

Pee*_*Haa 5 php postgresql pdo haversine

在我的网站上,我正试图在附近找到位置.

我正在尝试使用Haversine公式.

我正在使用以下查询来获取25公里范围内的所有位置.

SELECT id, ( 6371 * acos( cos( radians(51.8391) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(4.6265) ) + sin( radians(51.8391) ) * sin( radians( lat ) ) ) ) AS distance
FROM shops
HAVING distance < 25
ORDER BY name asc
Run Code Online (Sandbox Code Playgroud)

但是我觉得有些函数可能只是MySQL,因为我收到以下错误:

警告:PDOStatement :: execute()[pdostatement.execute]:SQLSTATE [42883]:未定义的函数:7错误:函数弧度(文本)不存在LINE 1:... id,(6371*acos(cos(radians( 51.8391))*cos(弧度(l ... ^ HINT:没有函数匹配给定的名称和参数类型.你可能需要添加显式类型转换.in ...

或者它可能与我必须更改lat查询中的文本有关.但我不知道应该是什么.

51.8391和4.6265是我的"起点"的长点和长点.

任何帮助都非常感谢,因为我不知道要改变什么:-)

编辑

看起来问题出在我试图做的地方:radians(lat).

lat是我表中的一列.

当我尝试使用rad()hakre建议错误更改为:function rad(numeric) does not exist

编辑2

现在我们到了某个地方.

确实设置为文本的列的数据类型(由mu建议的太短).

我把它改为双精度.

但是现在我又得到了一个错误:

警告:PDOStatement :: execute()[pdostatement.execute]:SQLSTATE [42703]:未定义列:7错误:列"距离"不存在第1行:... adians(lat))))AS距离商店HAVING距离<... ^ ...

但我以为我在选择中做了一个别名.有任何想法吗?

此外,如果你们认为这应该是另一个问题,请告诉我,我会关闭这个.

mu *_*ort 7

PostgreSQL确实有一个radians功能:

radians(dp)
度数到弧度

但是radians想要一个浮点参数,你试图给它一些字符串:

未定义的函数:7错误:函数弧度(文本)
[...]提示:没有函数匹配给定的名称和参数类型.您可能需要添加显式类型转换.

强调我的.显然,你latlngchar(n),varchar(n)text列.你应该修改列类型latlngnumeric,float或一些其他浮点类型 ; 同时,您可以手动投射字符串,并希望您没有任何损坏的数据:

radians(cast(lat as double precision))
Run Code Online (Sandbox Code Playgroud)

MySQL做了很多隐式类型转换,PostgreSQL更严格,要求你准确地说出你的意思.


第二个问题的更新:在HAVING子句之前计算SELECT子句,因此SELECT查询中的其他位置通常不提供列别名.你有几个选择,你可以重复你的丑陋的Haversine:

SELECT id, ( 6371 * acos( cos( radians(51.8391) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(4.6265) ) + sin( radians(51.8391) ) * sin( radians( lat ) ) ) ) AS distance
FROM shops
HAVING ( 6371 * acos( cos( radians(51.8391) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(4.6265) ) + sin( radians(51.8391) ) * sin( radians( lat ) ) ) ) < 25
ORDER BY name asc
Run Code Online (Sandbox Code Playgroud)

或者使用派生表来避免重复自己:

select id, distance
from (
    select id, name, ( 6371 * acos( cos( radians(51.8391) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(4.6265) ) + sin( radians(51.8391) ) * sin( radians( lat ) ) ) ) as distance
    from shops
) as dt
where distance < 25.0
order by name asc
Run Code Online (Sandbox Code Playgroud)