我有一个休闲的 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 距离,因此它不返回任何记录,但如果我删除“有距离<1”,那么它会从 tbl_country_de 返回 id=24 的核心记录,但表列距离为 NULL 值。
我应该如何编写 mysql 查询,以便 mysql 返回两点(纬度和经度值)之间的距离等于 0 的记录
为什么 mysql 对距离返回 NULL 而不是 '0'?
我已将纬度和经度数据类型从 decimal(10,7) 更改为 float(10,7),并且可以正常工作。 不知道这是否是真正的问题??
最佳答案
这个问题已经存在一段时间了,但是还没有得到正确的回答。
DECIMAL 是不适合地理定位数据的数据类型。
问题中的公式称为球面余弦定律公式。如果您仔细查看此公式,您会注意到,当您处理非常接近的点时,它会取一个非常接近 1 的数字的反余弦 (ACOS()
)。这是一个数值不稳定的操作。 Unstable 在这种情况下意味着如果输入中有小的错误,函数的输出可能会有很大差异。
有一个更好的球体表面距离公式,称为文森蒂公式。它的最后一个操作是 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 中的三角函数(余弦、正弦、反正切等)是使用服务器计算机的 float 学子系统实现的。如果您以 DECIMAL 格式向他们提供数据,则数据将转换为 DOUBLE、计算,然后再转换回来。这将导致它失去精度。 FLOAT
数据类型(IEEE-488 单精度浮点)为商业 GPS 样式的纬度和经度数据提供了足够的精度。
问题中提到的 NULL 结果可能是由于在 DOUBLE 和 DECIMAL 之间转换时固有的错误导致 ACOS 的输入无限大于 1。 1.00001 的反余弦运算失败并产生 NULL。切换到 FLOAT 和 Vincenty 公式将消除这个故障源。
关于php - MYSQL无法选取点间距离(lat,lng)=0的记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17953766/