SQL:根据lat / lon查找最近邻居

时间:2016-09-22 09:09:04

标签: mysql sql latitude-longitude

我有一张包含咖啡馆的lat / lon的桌子。我想做一个SQL查询,它给了我最近的咖啡馆到每个咖啡馆。有人可以提供有关如何执行此操作的建议吗?

表格基本上如下:

Cafe ID

+-------------------------+----------------------+----------------------+
| cafe_id                 | gps_latitude         | gps_longitude        |
+-------------------------+----------------------+----------------------+
| 011-1003                | 55.86649500000000000 |  8.16856200000000000 |
| 192-143                 | 57.04419159749860000 | 10.36447024359820000 |
| 037-0233                | 55.08773849210000000 |  8.56101036070000000 |
| 121-934                 | 56.89120900000000000 |  9.16818100000000000 |
+-------------------------+----------------------+----------------------+

非常感谢任何帮助!

3 个答案:

答案 0 :(得分:2)

试试这个:

{{1}}

可以在此处阅读此主题的更多内容: http://www.plumislandmedia.net/mysql/haversine-mysql-nearest-loc/

答案 1 :(得分:2)

您可以使用Spherical Law of Cosines获取earth-radii中表达的距离。

有些人更喜欢Haversine formula,因为它提供了更好的精度,但鉴于MySql的浮点精度足够高,两者之间的差异可以忽略不计。第一个更容易实现:

select     c1.cafe_id,
           substring_index (
             group_concat( C2.cafe_id order by 
               acos(  sin(radians(c1.gps_latitude)) * sin(radians(c2.gps_latitude)) 
                    + cos(radians(c1.gps_latitude)) * cos(radians(c2.gps_latitude)) 
                      * cos(radians(c2.gps_longitude-c1.gps_longitude)) ) ),
             ',', 1) nearest
from       cafe c1
inner join cafe c2 on c1.cafe_id <> c2.cafe_id
group by   c1.cafe_id

样本数据的输出是:

|  cafe_id |  nearest |
|----------|----------|
| 011-1003 | 037-0233 |
| 037-0233 | 011-1003 |
| 121-934  | 192-143  |
| 192-143  | 121-934  |

这是MySql fiddle

解释

距离计算在order by聚合函数的group_concat子句中使用,该子句以逗号分隔的 cafe_id 值列表按照其距离的顺序排列你分组的咖啡馆。 substring_index函数从该列表中提取第一个项目。

连接条件很重要,因为没有它你会把咖啡馆本身当作最近的邻居(它的距离显然是0)。

设置距离限制

在评论中,您要求仅包含某个半径范围内的邻居。

在这种情况下,您可以输出“距离”,转换为km(英里将是一个不同的因素):

select     c1.cafe_id,
           substring_index (
             group_concat( C2.cafe_id order by 
               acos(  sin(radians(c1.gps_latitude)) * sin(radians(c2.gps_latitude)) 
                    + cos(radians(c1.gps_latitude)) * cos(radians(c2.gps_latitude)) 
                      * cos(radians(c2.gps_longitude-c1.gps_longitude)) ) ),
             ',', 1) nearest,
           min (
               acos(  sin(radians(c1.gps_latitude)) * sin(radians(c2.gps_latitude)) 
                    + cos(radians(c1.gps_latitude)) * cos(radians(c2.gps_latitude)) 
                      * cos(radians(c2.gps_longitude-c1.gps_longitude)) ) )
             * 6371 km
from       cafe c1
inner join cafe c2 on c1.cafe_id <> c2.cafe_id
group by   c1.cafe_id

现在您可以根据距离决定是否要忽略邻居。如果您真的想要排除最近邻居太远的咖啡馆,那么最后添加一个having条款:

having     km < 5

如果你喜欢里程,那么在SQL中使用3959作为乘法因子而不是6371。

答案 2 :(得分:1)

Bellow查询有助于找出两个(邻居)最近的位置。

使用当前的lat和lng值在MySQL中设置变量

(SELECT tbl.cafe_id , tbl.gps_latitude, tbl.gps_longitude, 111.045 * DEGREES(ACOS(COS(RADIANS(@lat))
 * COS(RADIANS(gps_latitude))
 * COS(RADIANS(gps_longitude) - RADIANS(@lng))
 + SIN(RADIANS(@lat))
 * SIN(RADIANS(gps_latitude))))
 AS distance_in_km
FROM table_name as tbl ORDER BY distance_in_km ASC LIMIT 0,1)
UNION ALL
(SELECT tbl.cafe_id , tbl.gps_latitude, tbl.gps_longitude, 111.045 * DEGREES(ACOS(COS(RADIANS(@lat))
 * COS(RADIANS(gps_latitude))
 * COS(RADIANS(gps_longitude) - RADIANS(@lng))
 + SIN(RADIANS(@lat))
 * SIN(RADIANS(gps_latitude))))
 AS distance_in_km
FROM table_name as tbl ORDER BY distance_in_km DESC LIMIT 0,1);

执行查询

footer