Haversine 公式单位错误 - PL/SQL
Haversine Formula unit errors - PL/SQL
总体目标:查找给定邮政编码 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 ;
我试过的方法:我发现了一些看起来会 solve all my problems:
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;
所以,我认为地理数据组可能有不同的方式来记录纬度和经度,我发现 Wikipedia's Haversine formula 并将其转换为函数
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 英里,但我需要计算我的纬度/经度转换在那里也出错了。
看起来像是参数问题。 header 是:
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" 别名,并保持其他一切不变。
总体目标:查找给定邮政编码 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 ;
我试过的方法:我发现了一些看起来会 solve all my problems:
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;
所以,我认为地理数据组可能有不同的方式来记录纬度和经度,我发现 Wikipedia's Haversine formula 并将其转换为函数
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 英里,但我需要计算我的纬度/经度转换在那里也出错了。
看起来像是参数问题。 header 是:
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" 别名,并保持其他一切不变。