完整的代码及如何安装为MySQL插件的详细信息在此处:
https://github.com/lucasepe/lib_mysqludf_haversine
我去年曾将此内容发布为评论。由于TylerCollier先生友好地建议我将其发布为答案,因此在这里呈现。
另一种方法是编写一个自定义UDF函数,该函数返回两个点之间的球面距离。该函数可以接受以下输入:
lat1 (real), lng1 (real), lat2 (real), lng2 (real), type (string - optinal - 'km', 'ft', 'mi')
所以我们可以这样写:
SELECT id, name FROM MY_PLACES WHERE haversine_distance(lat1, lng1, lat2, lng2) < 40;
获取距离小于40公里的所有记录。或者:
SELECT id, name FROM MY_PLACES WHERE haversine_distance(lat1, lng1, lat2, lng2, 'ft') < 25;
将所有距离小于25英尺的记录获取。
核心函数是:
double
haversine_distance( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error ) {
double result = *(double*) initid->ptr;
double R = 6372.797560856;
double DEG_TO_RAD = M_PI/180.0;
double RAD_TO_DEG = 180.0/M_PI;
double lat1 = *(double*) args->args[0];
double lon1 = *(double*) args->args[1];
double lat2 = *(double*) args->args[2];
double lon2 = *(double*) args->args[3];
double dlon = (lon2 - lon1) * DEG_TO_RAD;
double dlat = (lat2 - lat1) * DEG_TO_RAD;
double a = pow(sin(dlat * 0.5),2) +
cos(lat1*DEG_TO_RAD) * cos(lat2*DEG_TO_RAD) * pow(sin(dlon * 0.5),2);
double c = 2.0 * atan2(sqrt(a), sqrt(1-a));
result = ( R * c );
if (args->arg_count == 5) {
str_to_lowercase(args->args[4]);
if (strcmp(args->args[4], "ft") == 0) result *= 3280.8399;
if (strcmp(args->args[4], "mi") == 0) result *= 0.621371192;
}
return result;
}