如何在相等的存储桶中按距离排序?

时间:2019-08-13 18:12:32

标签: mysql coordinates gis distance coordinate-systems

我们对具有以下内容的产品进行用户评论:

  1. 评论说明
  2. 撰写评论的日期
  3. 撰写评论的城市

我们在这里有两个表:

1)评论(列:说明(varchar),日期(DateTime),CityId(int))

2)城市(列:Id(int),名称(varchar),纬度,经度)

我们要对这些用户评论进行排序,以便如果输入是任何给定的城市,假设城市为“ C”,则输出排序顺序应为:

  • 针对城市“ C”的0到“ X”公里内的城市撰写的评论,其次是
  • 针对城市“ C”的“ X”到“ 2X”公里的城市撰写的评论,其次是
  • 针对“ 2X”至“ 3X”公里等城市的评论,以此类推,直到城市结束。

解决此问题的一种简单方法是:仅在运行时执行此操作,然后逐个获取这些公里范围内的城市,然后再进行检查,但这太慢了。另外,我们将多次执行相同的操作。为了避免重新计算,我们可以为每个城市保存附近桶市的信息,但不确定是否理想。

有没有更简单,更有效的方法来解决此问题,例如通过kat / long或其他任何方法?

1 个答案:

答案 0 :(得分:1)

您可以使用Haversine Formula来检索按距离排序的评论;请参见Haversine implementation编写可直接在查询中使用的MySQL函数。

在下面的查询中(也在SQL Fiddle中),我使用了一个更简单的公式来说明如何使用“洛杉矶”(789)作为给定的城市来执行查询:

select *
from (
  select
    r.*,
    sqrt(power(g.lat - c.lat, 2) + power(g.lng - c.lng, 2)) as dist -- simple dist
  from reviews r
  join cities c on c.id = r.cityid -- city the review belongs to
  join cities g on g.id = 789 -- given city as input
) x
order by dist

请注意,表cities被连接了两次:首先是评论所属的城市,然后是给定的[基本]城市。这样我们就可以计算距离。

结果:

description  recorded             cityid  dist   
-----------  -------------------  ------  -------
review 4     2019-01-01 07:34:56  789     0      
review 2     2019-01-01 07:34:56  456     5.65685
review 3     2019-01-01 07:34:56  456     5.65685
review 1     2019-01-01 07:34:56  123     6.32456

作为参考,这是我使用的数据脚本:

create table reviews (
  description varchar(100),
  recorded datetime,
  cityid int
);

insert into reviews (description, recorded, cityid) values 
  ('review 1', '2019-01-01 12:34:56', 123),
  ('review 2', '2019-01-01 12:34:56', 456),
  ('review 3', '2019-01-01 12:34:56', 456),
  ('review 4', '2019-01-01 12:34:56', 789);

create table cities (
  id int,
  name varchar(20),
  lat double,
  lng double
);

insert into cities (id, name, lat, lng) values 
  (123, 'Chicago', 10, 11),
  (456, 'Indianapolis', 12, 9),  
  (789, 'Los Angeles', 8, 5);