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&lt;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的主要内容,如果未能解决你的问题,请参考以下文章

根据haversine距离公式选择不同的列值?

使用 NodeJs 的 Mongodb 地理空间查询(Haversine 公式)

使用 NodeJs 的 Mongodb 地理空间查询(Haversine 公式)

MySQL 大圆距离(Haversine 公式)

用haversine和float计算距离......有点工作

尝试使用haversine公式在laravel中获取非对象的属性