使用 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 的默认精度。