使用 SQL 使用 2 个全局点计算距离
Calulate distance using 2 global points using SQL
我正在尝试从 2 个全局点获取以米为单位的距离(lat/long)
我发现了一些对半正弦公式 here and here 的引用。
根据给定的公式,我做了一个sql脚本(mysql)
DELIMITER $$
CREATE FUNCTION get_geo_distance (lat1 DECIMAL, lon1 DECIMAL, lat2 DECIMAL, lon2 DECIMAL)
RETURNS DECIMAL
BEGIN
DECLARE RR LONG;
DECLARE o1 DECIMAL;
DECLARE o2 DECIMAL;
DECLARE Ao DECIMAL;
DECLARE AA DECIMAL;
DECLARE a DECIMAL;
DECLARE c DECIMAL;
SET RR = 6371000;
SET o1 = RADIANS(lat1);
SET o2 = RADIANS(lat2);
SET Ao = RADIANS(lat2 - lat1);
SET AA = RADIANS(lon2 - lon1);
SET a = SIN(Ao/2) * SIN(Ao/2) +
COS(o1) * COS(o2) *
SIN(AA/2) * SIN(AA/2);
SET c = 2 * ATAN2(SQRT(a), SQRT(1-a));
RETURN RR * c;
END $$
DELIMITER ;
但是,当我调用 get_geo_distance 时,它会 return 0(零)
有人可以帮我吗?
使用示例:
SELECT get_geo_distance(1,1,0,0);
SELECT get_geo_distance(10, 10, 0, 0);
SELECT get_geo_distance(-22.7514855, -47.3987318, -22.7599327, -47.3914984);
不要为此使用十进制数据类型。请改用 FLOAT
。小数舍入因破坏这些计算而臭名昭著。
这个存储过程很好地完成了这项工作。
DELIMITER $$
DROP FUNCTION IF EXISTS haversine$$
CREATE FUNCTION haversine(
lat1 FLOAT, lon1 FLOAT,
lat2 FLOAT, lon2 FLOAT
) RETURNS FLOAT
NO SQL DETERMINISTIC
COMMENT 'Returns the distance in degrees on the Earth
between two known points of latitude and longitude'
BEGIN
RETURN DEGREES(ACOS(
COS(RADIANS(lat1)) *
COS(RADIANS(lat2)) *
COS(RADIANS(lon2) - RADIANS(lon1)) +
SIN(RADIANS(lat1)) * SIN(RADIANS(lat2))
));
END$$
DELIMITER ;
这个函数returns度。您需要将它乘以一个常数以获得更常规的距离测量值。在温带纬度,值 111.045 是一个很好的值,可以用来计算公里数,69.0 可以计算法定英里数(如果你碰巧住在像美国这样的前英国殖民地,这很有用)。
这里有关于这个问题的更详尽的文章。 http://www.plumislandmedia.net/mysql/haversine-mysql-nearest-loc/
用 REAL 替换 DECIMAL 解决了我的问题:
drop function if exists get_geo_distance;
DELIMITER $$
CREATE FUNCTION get_geo_distance (lat1 REAL, lon1 REAL, lat2 REAL, lon2 REAL)
RETURNS real deterministic
BEGIN
DECLARE RR REAL;
DECLARE o1 REAL;
DECLARE o2 REAL;
DECLARE Ao REAL;
DECLARE AA REAL;
DECLARE a REAL;
DECLARE c REAL;
SET RR = 6371000;
SET o1 = RADIANS(lat1);
SET o2 = RADIANS(lat2);
SET Ao = RADIANS(lat2 - lat1);
SET AA = RADIANS(lon2 - lon1);
SET a = SIN(Ao/2) * SIN(Ao/2) +
COS(o1) * COS(o2) *
SIN(AA/2) * SIN(AA/2);
SET c = 2 * ATAN2(SQRT(a), SQRT(1-a));
RETURN RR * c;
END $$
DELIMITER ;
select get_geo_distance(-22.7514855, -47.3987318, -22.7599327, -47.3914984);
returns
1196.826386258915
我没有深入研究,但我猜测当类型为 DECIMAL 而不是 REAL 时,浮点运算中可能会丢失一些东西,这可能是由于 DECIMAL 的默认精度。
我正在尝试从 2 个全局点获取以米为单位的距离(lat/long)
我发现了一些对半正弦公式 here and here 的引用。 根据给定的公式,我做了一个sql脚本(mysql)
DELIMITER $$
CREATE FUNCTION get_geo_distance (lat1 DECIMAL, lon1 DECIMAL, lat2 DECIMAL, lon2 DECIMAL)
RETURNS DECIMAL
BEGIN
DECLARE RR LONG;
DECLARE o1 DECIMAL;
DECLARE o2 DECIMAL;
DECLARE Ao DECIMAL;
DECLARE AA DECIMAL;
DECLARE a DECIMAL;
DECLARE c DECIMAL;
SET RR = 6371000;
SET o1 = RADIANS(lat1);
SET o2 = RADIANS(lat2);
SET Ao = RADIANS(lat2 - lat1);
SET AA = RADIANS(lon2 - lon1);
SET a = SIN(Ao/2) * SIN(Ao/2) +
COS(o1) * COS(o2) *
SIN(AA/2) * SIN(AA/2);
SET c = 2 * ATAN2(SQRT(a), SQRT(1-a));
RETURN RR * c;
END $$
DELIMITER ;
但是,当我调用 get_geo_distance 时,它会 return 0(零) 有人可以帮我吗?
使用示例:
SELECT get_geo_distance(1,1,0,0);
SELECT get_geo_distance(10, 10, 0, 0);
SELECT get_geo_distance(-22.7514855, -47.3987318, -22.7599327, -47.3914984);
不要为此使用十进制数据类型。请改用 FLOAT
。小数舍入因破坏这些计算而臭名昭著。
这个存储过程很好地完成了这项工作。
DELIMITER $$
DROP FUNCTION IF EXISTS haversine$$
CREATE FUNCTION haversine(
lat1 FLOAT, lon1 FLOAT,
lat2 FLOAT, lon2 FLOAT
) RETURNS FLOAT
NO SQL DETERMINISTIC
COMMENT 'Returns the distance in degrees on the Earth
between two known points of latitude and longitude'
BEGIN
RETURN DEGREES(ACOS(
COS(RADIANS(lat1)) *
COS(RADIANS(lat2)) *
COS(RADIANS(lon2) - RADIANS(lon1)) +
SIN(RADIANS(lat1)) * SIN(RADIANS(lat2))
));
END$$
DELIMITER ;
这个函数returns度。您需要将它乘以一个常数以获得更常规的距离测量值。在温带纬度,值 111.045 是一个很好的值,可以用来计算公里数,69.0 可以计算法定英里数(如果你碰巧住在像美国这样的前英国殖民地,这很有用)。
这里有关于这个问题的更详尽的文章。 http://www.plumislandmedia.net/mysql/haversine-mysql-nearest-loc/
用 REAL 替换 DECIMAL 解决了我的问题:
drop function if exists get_geo_distance;
DELIMITER $$
CREATE FUNCTION get_geo_distance (lat1 REAL, lon1 REAL, lat2 REAL, lon2 REAL)
RETURNS real deterministic
BEGIN
DECLARE RR REAL;
DECLARE o1 REAL;
DECLARE o2 REAL;
DECLARE Ao REAL;
DECLARE AA REAL;
DECLARE a REAL;
DECLARE c REAL;
SET RR = 6371000;
SET o1 = RADIANS(lat1);
SET o2 = RADIANS(lat2);
SET Ao = RADIANS(lat2 - lat1);
SET AA = RADIANS(lon2 - lon1);
SET a = SIN(Ao/2) * SIN(Ao/2) +
COS(o1) * COS(o2) *
SIN(AA/2) * SIN(AA/2);
SET c = 2 * ATAN2(SQRT(a), SQRT(1-a));
RETURN RR * c;
END $$
DELIMITER ;
select get_geo_distance(-22.7514855, -47.3987318, -22.7599327, -47.3914984);
returns
1196.826386258915
我没有深入研究,但我猜测当类型为 DECIMAL 而不是 REAL 时,浮点运算中可能会丢失一些东西,这可能是由于 DECIMAL 的默认精度。