【问题标题】:Same query but different result when ran in different database servers在不同的数据库服务器中运行相同的查询但结果不同
【发布时间】:2020-01-04 02:27:15
【问题描述】:

我有一个运行 MariaDB 服务器版本 10.2.14 的本地环境和一个运行 MariaDB 服务器版本 10.1.40 的生产环境。

在基于半正弦公式运行计算以计算 2 个地理位置之间的距离时,我的本地环境返回 0 作为结果,但 prod 环境返回 null。

示例查询如下:

select (acos(cos(radians((41.480473))) * cos(radians(41.480473)) *
 cos(radians((-81.630990)) - radians(-81.630990)) + 
 sin(radians((41.480473))) * sin(radians(41.480473))) * 3958.755
 ) as distance

结果应该为零,因为它本质上是在尝试获取具有相同地理位置信息的 2 个位置之间的距离。

谁能解释为什么我的 prod 环境在运行上述示例时给我一个空值而不是零?

【问题讨论】:

    标签: sql mariadb


    【解决方案1】:

    差异来自最外层acos-函数的舍入误差。另一个系统可能会给你正好 1,而另一个系统可能会因为舍入误差给你超过 1。 acos 的有效参数从 1 为 0 且 acos 值 > 1 为 NULL。

    您可以在最外面的acos之前使用ROUND,并将计算变成一个更容易使用的函数:

    create function f_distance_in_miles( 
    in_lat1 decimal(9,7),
    in_long1 decimal(9,7),
    in_lat2 decimal(9,7),
    in_long2 decimal(9,7)
    )
    returns float
    deterministic
    begin
    
    declare v_i real;
    
    set v_i = cos(radians(in_lat1)) *  cos(radians(in_lat2)) *  cos(radians(in_long1) 
       - radians(in_long2))
       + sin(radians(in_lat1)) * sin(radians(in_lat2));
    
    if (v_i<-1) then
      set v_i = -1;
    elseif (v_i>1) then
      set v_i = 1;
    end if;
    
    return acos(v_i)*3958.755;
    
    end
    

    然后像这样使用它:

    select f_distance_in_miles(41.480473, -81.630990, 41.480473, -81.630990)
    

    【讨论】:

    • 没有。 ROUNDing 中间结果只会更改导致问题的值。
    • @RickJames 小数点后的最后一位数字发生舍入错误(1.0000000000000002)。将其四舍五入到 7 位将消除任何值的问题(你总是可以证明我错了)。真正的问题是由于四舍五入(0.5 英里)而损失了一些精度,但话说回来,公式也不是那么精确。为了获得最佳结果,最好只检查中间结果是否超出范围并修复它。改进了答案。
    • 略短:if (abs(v_i) &gt; 1 then set v_i = round(v_i); end if; 更好:if (abs(v_i) &gt; 1) then return 0; end if; 什么时候可以出现-1?
    • 4 年前我拒绝了 Haversine:mysql.rjweb.org/doc.php/latlng#postlog
    猜你喜欢
    • 1970-01-01
    • 2010-10-10
    • 1970-01-01
    • 2014-07-06
    • 2012-02-05
    • 2023-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多