php - 在 MySQL 中的十进制列中查找最接近的匹配项

标签 php mysql geolocation match

下午,

我很难理解这个问题。我有一个 MySQL 表,其中包含英国邮政编码及其经度和纬度值的列表。我希望能够对表格进行搜索,以找到最接近给定经纬度对的邮政编码。

我一直在尝试使用的查询是:

"SELECT id, outcode AS thecode, @la := MATCH(lat) AGAINST(?) AS score_lat, @ln := MATCH(lng) AGAINST(?) AS score_lng, @la + @ln AS score_total FROM postcodes ORDER BY score_total DESC LIMIT 10

然而,这只会返回看似随机的邮政编码,例如 Lat:55.775549 和 Long:-4.047556

Array
(
[0] => Array
    (
        [id] => 929
        [thecode] => FK14
        [score_lat] => 0
        [score_lng] => 0
        [score_total] => 0
    )

[1] => Array
    (
        [id] => 2785
        [thecode] => UB3
        [score_lat] => 0
        [score_lng] => 0
        [score_total] => 0
    )

[2] => Array
    (
        [id] => 993
        [thecode] => G70
        [score_lat] => 0
        [score_lng] => 0
        [score_total] => 0
    )

[3] => Array
    (
        [id] => 2849
        [thecode] => WC2B
        [score_lat] => 0
        [score_lng] => 0
        [score_total] => 0
    )

[4] => Array
    (
        [id] => 1057
        [thecode] => GU29
        [score_lat] => 0
        [score_lng] => 0
        [score_total] => 0
    )

[5] => Array
    (
        [id] => 2913
        [thecode] => WS13
        [score_lat] => 0
        [score_lng] => 0
        [score_total] => 0
    )

[6] => Array
    (
        [id] => 1121
        [thecode] => HP20
        [score_lat] => 0
        [score_lng] => 0
        [score_total] => 0
    )

[7] => Array
    (
        [id] => 1185
        [thecode] => IG6
        [score_lat] => 0
        [score_lng] => 0
        [score_total] => 0
    )

[8] => Array
    (
        [id] => 1249
        [thecode] => IV25
        [score_lat] => 0
        [score_lng] => 0
        [score_total] => 0
    )

[9] => Array
    (
        [id] => 1313
        [thecode] => KA8
        [score_lat] => 0
        [score_lng] => 0
        [score_total] => 0
    )
)

数据库的模式是:

CREATE TABLE `postcodes` (
  `id` int(11) NOT NULL auto_increment,
  `outcode` varchar(4) NOT NULL,
  `lat` varchar(20) NOT NULL,
  `lng` varchar(20) NOT NULL,
  PRIMARY KEY  (`id`),
  FULLTEXT KEY `lat` (`lat`),
  FULLTEXT KEY `lng` (`lng`)
) ENGINE=MyISAM AUTO_INCREMENT=2975 DEFAULT CHARSET=latin1 AUTO_INCREMENT=2975 ;

希望有人能帮忙!如果您需要更多信息,请询问...

谢谢,

尾尖

最佳答案

MySQL MATCH() 函数用于全文搜索以“匹配”字符串。 (所以它返回零值也就不足为奇了。)

如果“最接近”是指您想要计算 map 上两点之间的距离(如“乌鸦飞行”所测量的那样),坐标以(十进制度)纬度和经度给出,那么您真的需要使用大圆距离 (GCD) 计算。

http://en.wikipedia.org/wiki/Great-circle_distance

您可以跳过所有这些血淋淋的细节,只需使用我的实现即可。下面是我的一个 SQL 语句的 SELECT 列表的摘录,这个表达式计算两点之间的距离(以英里为单位)...

     , ACOS(
          COS(RADIANS( d2.latitude ))
        * COS(RADIANS( d1.latitude ))
        * COS(RADIANS( d2.longitude ) - RADIANS( d1.longitude ))
        + SIN(RADIANS( d2.latitude ))
        * SIN(RADIANS( d1.latitude ))
           )*3958.82 AS distance_miles

在这个例子中,d1代表起点,d2代表终点。 latitudelongitude 以 DECIMAL 值提供。

有了 d1 的单个“已知”点,我可以按此表达式排序,首先获得“最接近”的 d2。 (对于多个原点,我可以按 d1.id 排序,然后按此表达式为每个 d1 首先获取最接近的 d2。但是关于我的问题...


我从您的问题中复制了查询并对其进行了修改(如下)。基本上,我删除了“分数”列,并将其替换为执行距离计算的表达式:

SELECT id
     , outcode AS thecode
     , ACOS(
           COS(RADIANS( d2.latitude ))
         * COS(RADIANS( @d1_latitude ))
         * COS(RADIANS( d2.longitude ) - RADIANS( @d1_longitude ))
         + SIN(RADIANS( d2.latitude ))
         * SIN(RADIANS( @d1_latitude ))
           )*3958.82 AS distance_miles
  FROM postcodes d2
  JOIN (SELECT @d1_latitude := ?, @d1_longitude := ?) v
 ORDER BY distance_miles LIMIT 10

在这种情况下,@d1_ 变量(从绑定(bind)变量分配)是您“已知”点的纬度和经度。对于 postcodes 表中的每一行(为方便起见,我将其别名为 d2),此表达式计算表中的纬度/经度与“已知”点之间的距离.

注意:别名为 v 的内联 View 就在那里,因此您可以只绑定(bind)一次纬度,并将值分配给可以引用的用户变量。可以省略该内联 View ,您可以看到需要两次绑定(bind)纬度的位置。

注意:这会以“英里”为单位计算距离。通过用不同的值代替 3958.82 常量,您可以轻松获得以公里 (km) 为单位的距离。

注意:不需要返回距离;如果您只对按距离返回最接近的 10 个感兴趣,则可以将该表达式放在 ORDER BY 子句中,例如

SELECT id
     , outcode AS thecode
  FROM postcodes d2
  JOIN (SELECT @d1_latitude := ?, @d1_longitude := ?) v
 ORDER
    BY ACOS(
           COS(RADIANS( d2.latitude ))
         * COS(RADIANS( @d1_latitude ))
         * COS(RADIANS( d2.longitude ) - RADIANS( @d1_longitude ))
         + SIN(RADIANS( d2.latitude ))
         * SIN(RADIANS( @d1_latitude ))
           )*3958.82 AS distance_miles
 LIMIT 10

如果您正在寻找两点之间的距离以外的其他信息,请告诉我,因为在那种情况下,这个答案对您真的没有帮助。

关于php - 在 MySQL 中的十进制列中查找最接近的匹配项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11765738/

相关文章:

php - urlencode 和 rawurlencode 有什么区别?

php - 在 Woocommerce 中验证并保存特定支付网关的附加结帐字段

javascript - 获得激活地理定位结果的 promise

ruby-on-rails - 存储 HTML5 地理位置数据

android - 添加 config.xml 后,地理位置无法与 Phonegap Build 一起使用

php - 方法可以在类之外定义吗?

php - 从输入文本创建标签云的最佳方法

MySQL别名问题

mysql - 在mysql中使用纬度和经度查找两点之间的距离

php - 函数中使用的 PDO 范围