数据库
首页 > 数据库> > PHP-MYSQL无法选择点之间距离(​​lat,lng)= 0的记录

PHP-MYSQL无法选择点之间距离(​​lat,lng)= 0的记录

作者:互联网

我有休闲的mysql查询

SELECT de.geoId,(6371 * ACOS( COS( RADIANS(zde.latitude) )* 
    COS(RADIANS( de.latitude ) ) * COS( RADIANS( de.longitude ) - RADIANS(zde.longitude) ) + 
    SIN( RADIANS(zde.latitude) ) * SIN( RADIANS( de.latitude ) ) ) )  AS distance 
FROM tbl_zipde AS zde 
    LEFT JOIN  tbl_country_de AS de 
             ON (de.admin1_code=zde.admin_code1)  
                 Where zde.id=8 and  de.geoId=24 having distance<1

该查询应从表tbl_zountry_de返回一条记录,该记录的纬度和经度值与tbl_zipde的id = 8的记录相同,但是由于这两个点之间的计算距离为0,因此mysql将0识别为NULL,因此它不会返回任何记录,但是如果我删除“ having distance< 1”,则它将从tbl_country_de返回id = 24的corect记录,但表列距离为NULL值. 我应该如何编写mysql查询,以便mysql返回两点之间(经度和纬度值)的距离等于0的记录 为什么mysql的距离返回NULL而不是’0’? 我将纬度和经度数据类型从十进制(10,7)更改为float(10,7),并且可以工作.
不知道这是否是真正的问题吗?

解决方法:

这个问题已经存在了一段时间,但尚未正确回答.

对于地理位置数据,DECIMAL是不合适的数据类型.

问题中的公式称为球余弦定律公式.如果仔细看一下这个公式,您会注意到,当您处理非常靠近的点时,它的反余弦(ACOS())的数值几乎消失为1.这是一个数值不稳定的运算.在这种情况下,不稳定意味着如果输入中的错误很小,则函数的输出可能会发生很大的变化.

对于沿球体表面的距离,有一个更好的公式称为Vincenty公式.它的最后一个运算是ATAN2():对于微小角度,其数值稳定得多.就是这个:

111.045 * DEGREES(ATAN2(SQRT(
    POW(COS(RADIANS(lat2))*SIN(RADIANS(lon2-lon1)),2) +
    POW(COS(RADIANS(lat1))*SIN(RADIANS(lat2)) -
         (SIN(RADIANS(lat1))*COS(RADIANS(lat2)) *
          COS(RADIANS(lon2-lon1))) ,2)),
  SIN(RADIANS(lat1))*SIN(RADIANS(lat2)) +
  COS(RADIANS(lat1))*COS(RADIANS(lat2))*COS(RADIANS(lon2-lon1))))

一个MySQL存储过程在这里:http://www.plumislandmedia.net/mysql/vicenty-great-circle-distance-formula/

您可以在这里查询数学:http://en.wikipedia.org/wiki/Great-circle_distance

另外,请记住,MySQL中的Trig函数(余弦,正弦,反正切等)是使用服务器计算机的浮点数学子系统实现的.如果以DECIMAL格式向他们提供数据,则数据将转换为DOUBLE,进行计算,然后再转换回去.这将导致其失去精度. FLOAT数据类型(IEEE-488单精度浮点数)为商业GPS样式的纬度和经度数据提供了足够的精度.

问题中提到的NULL结果可能是由于在DOUBLE和DECIMAL之间转换所固有的错误,导致ACOS的输入无穷大地大于1. 1.00001的反余弦值失败,并产生NULL.改用FLOAT和Vincenty公式将消除这种故障源.

标签:floating-point,trigonometry,latitude-longitude,mysql,php
来源: https://codeday.me/bug/20191030/1969112.html