Haversine公式单位错误 - PL/SQL

3

总体目标: 查找给定邮编30英里范围内的所有邮编。

数据来源: 邮编列表,包含纬度和经度作为 'x' 和 'y'。

示例:

create or replace view zips as
select 37171 zip, 36.362704 y, -87.30434 x,'Southside' City, 'TN' State from dual 
union
select 37212, 36.133012, -86.802764, 'Nashville', 'TN' from dual 
union
select 37027, 36.00245, -86.791159, 'Brentwood', 'TN' from dual 
union
select 37191, 36.501196, -87.539057, 'Woodlawn', 'TN' from dual 
union
select 37067, 35.928406, -86.805538, 'Franklin', 'TN' from dual ;

我尝试过的方法:我找到了一个看起来像是要解决我所有问题的东西:

CREATE OR REPLACE FUNCTION distance (Lat1 IN NUMBER,
                                     Lon1 IN NUMBER,
                                     Lat2 IN NUMBER,
                                     Lon2 IN NUMBER,
                                     Radius IN NUMBER DEFAULT 3963) RETURN NUMBER IS
 -- Convert degrees to radians
 DegToRad NUMBER := 57.29577951;

BEGIN
  RETURN(NVL(Radius,0) * ACOS((sin(NVL(Lat1,0) / DegToRad) * SIN(NVL(Lat2,0) / DegToRad)) +
        (COS(NVL(Lat1,0) / DegToRad) * COS(NVL(Lat2,0) / DegToRad) *
         COS(NVL(Lon2,0) / DegToRad - NVL(Lon1,0)/ DegToRad))));
END;

然而,它给我奇怪的数字 - 一直太小(我知道从富兰克林到纳什维尔不是1英里),但我无法确定其缩小的常数因子。 (我用来测试的代码如下 - 我只是将Google地图上的距离与这些距离进行了比较)
select b.zip
  ,b.city
  ,b.state
  ,distance(a.x,a.y,b.x,b.y) distance
from zips a, zips b
where a.zip=37067
order by distance;

所以,我想也许地理数据组有一种不同的记录纬度和经度的方式,于是我找到了维基百科的Haversine公式并将其转换为一个函数

CREATE OR REPLACE FUNCTION distance (Lat1_d IN NUMBER,
                                     Lon1_d IN NUMBER,
                                     Lat2_d IN NUMBER,
                                     Lon2_d IN NUMBER,
                                     Radius IN NUMBER DEFAULT 3959) RETURN NUMBER IS
 -- Convert degrees to radians
 DegToRad NUMBER := .0174532925;
 Lat1 NUMBER := Lat1_d * DegToRad;
 Lon1 NUMBER := Lon1_d * DegToRad;
 Lat2 NUMBER := Lat2_d * DegToRad;
 Lon2 NUMBER := Lon2_d * DegToRad;

BEGIN

  RETURN 2*Radius * 
    asin(
      sqrt(
        power(sin((Lat2-Lat1)/2),2) + cos(Lat1) * cos(Lat2) * power(sin((Lon2-Lon1)/2),2)
      )
    )
        ;
END;

同样的问题-结果几乎完全相同,这让我想知道问题出在哪里。我没有进行哪些转换?我错过了什么?
请注意,如果我只查看每组邮政编码的30-50英里,我很乐意假设地球是平的并使用勾股距离,但我还需要弄清楚我的纬度/经度转换有什么问题。

1
我认为这是一个很棒的第一篇帖子。标签正确,数据样本、代码和数据格式化,参考资料等都很好。欢迎来到SO! - Aleksej
1个回答

2

看起来是参数问题。头部信息为:

CREATE OR REPLACE FUNCTION distance (Lat1 IN NUMBER,
                                     Lon1 IN NUMBER,
                                     Lat2 IN NUMBER,
                                     Lon2 IN NUMBER,

而你需要这样调用:

distance(a.x,a.y,b.x,b.y)

但是您的观点是:
create or replace view zips as
select 37171 zip, 36.362704 y, -87.30434 x,'Southside' City, 'TN' State from dual 
union
select 37212, 36.133012, -86.802764, 'Nashville', 'TN' from dual 
union
select 37027, 36.00245, -86.791159, 'Brentwood', 'TN' from dual 
union
select 37191, 36.501196, -87.539057, 'Woodlawn', 'TN' from dual 
union
select 37067, 35.928406, -86.805538, 'Franklin', 'TN' from dual ;

根据这个观点,x代表经度,y代表纬度。因此函数调用应该是:

distance(a.y,a.x,b.y,b.x)

或者,您可以在视图中交换“x”和“y”别名,并保持其他所有内容不变。


1
我听说偶尔用手掌拍一下额头很有好处,可以让事情变得活跃起来。感谢你给了我这个机会。 - Maggie
@Maggie,没问题。我也有同感,可能由于多年忘记分号等原因,在我的头骨上留下了凹痕。 - user6096242
一个关于良好命名价值的重要教训。如果视图列是longitudelatitude而不是xy,你可能会立即发现这一点。 - APC

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接