Haversine 查询到 Oracle
Posted
技术标签:
【中文标题】Haversine 查询到 Oracle【英文标题】:Haversine query into Oracle 【发布时间】:2011-09-14 15:29:57 【问题描述】:我目前必须检查我的查询并将它们转移到使用 Oracle 而不是 SQLSERVER 并且我有点卡住这个查询,我正在使用来自 here 的查询
SELECT TOP 1 * FROM ( SELECT o.outcode AS lead_postcode, v.location,
v.location_name, v.outcode AS venue_postcode, 6371.0E *
( 2.0E *asin(case when 1.0E < (sqrt(square(sin(((RADIANS(CAST(o.lat AS FLOAT)))-
(RADIANS(CAST(v.lat AS FLOAT))))/2.0E)) + (cos(RADIANS(CAST(v.lat AS FLOAT)))
* cos(RADIANS(CAST(o.lat AS FLOAT))) * square(sin(((RADIANS(CAST(o.lng AS FLOAT)))-
(RADIANS(CAST(v.lng AS FLOAT))))/2.0E))))) then 1.0E else
(sqrt(square(sin(((RADIANS(CAST(o.lat AS FLOAT)))-(RADIANS(CAST(v.lat AS FLOAT))))
/2.0E)) + (cos(RADIANS(CAST(v.lat AS FLOAT))) * cos(RADIANS(CAST(o.lat AS FLOAT)))
* square(sin(((RADIANS(CAST(o.lng AS FLOAT)))-(RADIANS(CAST(v.lng AS FLOAT))))
/2.0E))))) end )) AS distance FROM venue_postcodes v, uk_postcodes o
WHERE o.outcode = @nrpostcode ) i WHERE distance<100 ORDER BY distance
现在我知道这是一个可怕的查询,但 Oracle 似乎遇到了很多问题。
首先它不喜欢6371E
中的E
和所有后续的E
其次,它不喜欢square
函数,所以我决定使用power
函数,但这仍然给了我错误。
第三,它不喜欢radians
函数
第四,它不喜欢 TOP 1
部分,所以我将其更改为在 WHERE
子句中使用 ROWNUM
我完全不知道在这里做什么。
关于我可以做些什么来使它工作的任何想法?
提前致谢
【问题讨论】:
从horrible
转置为decent
。使用空格。分成几部分(也许是功能)。分别尝试每个功能 - 并为 Oracle 找到等效功能。分别尝试每个子句(如 Top
) - 并找到 Oracle 的等效子句。
我似乎无法找到radians
的替代品,也无法弄清楚为什么会出现E
问题?网络上似乎没有太多关于 hasrsine 和 oracle 的内容
我认为,如果您想“正确地”执行此操作,您最好使用 Oracle 的 Spatial 扩展名并使用它的一个距离函数(我认为包括 Haversine)来存储您的位置。但恐怕我不是甲骨文专家。否则,删除那些“E”;它们不是必需的,并开始告诉我们您针对每个问题收到的确切错误消息。
@Matt Gibson - 我已经放弃了E
,我现在收到的错误是RADIANS - invalid identifier
哦,至于弧度,请记住一个圆中有 2π 弧度,所以我认为您只需将度数除以大约 57.3 :) 但我个人会存储当我添加它们时,数据库中的纬度和经度也以弧度表示,以使这更容易和更快......
【参考方案1】:
我建议您采用稍微不同的方法。
查看此网站:http://psoug.org/reference/functions.html
查找引用“计算距离”的部分
【讨论】:
我已经在我的代码中实现了它,它很有魅力 - 谢谢:) @Jamie:这很好,解决了将代码转移到 Oracle 的直接问题。当您尝试在大表中使用WHERE distance<100 ORDER BY distance
进行任何查询时,必须为您的两个 (venue_postcodes, uk_postcodes)
表的每个行组合计算该函数。正如@Matt Gibson 所建议的那样,如果您希望性能更快,则应该对中型到大型表使用 Oracle 空间扩展。
这是一个仅链接的答案,链接(当前)似乎已失效。【参考方案2】:
我知道如何在 SQL Server 中执行此操作,这应该很容易移植到 Oracle:
这是我创建的一个 UDF,用于使用 Haversine 公式获得两个邮政编码之间的近似 crows flight 距离:
ALTER FUNCTION [dbo].[fn_GetZipDistanceMiles](
@ZipFrom VARCHAR(20),
@ZipTo VARCHAR(20)
)
RETURNS FLOAT
AS
BEGIN
DECLARE @Latitude1 FLOAT
DECLARE @Longitude1 FLOAT
DECLARE @Latitude2 FLOAT
DECLARE @Longitude2 FLOAT
SELECT @Latitude1 = Latitude,
@Longitude1 = Longitude
FROM ZipCode
WHERE ZipCode = @ZipFrom
SELECT @Latitude2 = Latitude,
@Longitude2 = Longitude
FROM ZipCode
WHERE ZipCode = @ZipTo
-- CONSTANTS
DECLARE @EarthRadiusInMiles FLOAT
SET @EarthRadiusInMiles = 3963.1
-- RADIANS conversion
DECLARE @Lat1Radians FLOAT
DECLARE @Long1Radians FLOAT
DECLARE @Lat2Radians FLOAT
DECLARE @Long2Radians FLOAT
SET @Lat1Radians = @Latitude1 * PI() / 180
SET @Long1Radians = @Longitude1 * PI() / 180
SET @Lat2Radians = @Latitude2 * PI() / 180
SET @Long2Radians = @Longitude2 * PI() / 180
RETURN ACOS(COS(@Lat1Radians) * COS(@Long1Radians) * COS(@Lat2Radians) * COS(@Long2Radians) + COS(@Lat1Radians) * SIN(@Long1Radians) * COS(@Lat2Radians) * SIN(@Long2Radians) + SIN(@Lat1Radians) * SIN(@Lat2Radians)) * @EarthRadiusInMiles
END
【讨论】:
以上是关于Haversine 查询到 Oracle的主要内容,如果未能解决你的问题,请参考以下文章
使用 NodeJs 的 Mongodb 地理空间查询(Haversine 公式)
使用 NodeJs 的 Mongodb 地理空间查询(Haversine 公式)