只获得给定列值的一行

时间:2014-03-11 23:57:16

标签: mysql sql geolocation proximity

我的查询的基本结构是:

  • 我有一个包含个人资料信息的profiles
  • 我有一个位置坐标为<{1}}的表
  • 我有一个locations表,其中只包含(profile_id,location_id)对

每个配置文件都分配给一个或多个位置,我尝试做的是搜索配置文件,并按距离到位置坐标的顺序返回它们。我的查询是(仅包括相关部分)如下:

location_assignment

(选择行中的grosstastic事件将SELECT *, (3959*acos(cos(radians(30.292424))*cos(radians(lat))*cos(radians(lng)- radians(-97.73856))+sin(radians(30.292424))*sin(radians(lat)))) AS distance, `profiles`.`name` as profilename, `profiles`.`profile_id` as profile_id FROM (`profiles`) JOIN `location_assignment` ON `profiles`.`profile_id` =`location_assignment`.`profile_id` JOIN `locations` ON `location_assignment`.`location_id` = `locations`.`location_id` HAVING `distance` < 50 ORDER BY `distance` LIMIT 3" 表中的lat / lng字段转换为距给定输入lat / lng的距离

但是,我的查询会在结果中多次显示配置文件,对于分配给他的每个位置。我希望每个配置文件只出现一次,其中包含距离最短的位置信息。

我的下意识反应是使用locations,但我想确保获得与输入坐标的距离最小的位置。

2 个答案:

答案 0 :(得分:2)

去长角牛!

让我们从位置表中找到正确的行开始。

SELECT DISTINCT location_id
  FROM locations
 ORDER BY your_spherical_cosine_law_distance_formula
 LIMIT 1

这会获得唯一的位置ID。

现在,您希望将其用作子查询以获取相应的配置文件行。你喜欢这样:

 SELECT whatever
   FROM (
        SELECT DISTINCT location_id
          FROM locations
         ORDER BY your_spherical_cosine_law_distance_formula
         LIMIT 1
        ) AS one
   JOIN location_assignment AS la ON one.location_id = la.location_id
   JOIN profiles AS p on p.profile_id =la.profile_id

这应该为您提供适当的配置文件行列表,没有重复。

你没有提出这个问题,但我希望你没有太多的位置行。您正在使用的查询必须扫描整个表格,并为每一行进行大量数学运算。您的HAVING条款确实无济于事。为了加快速度,您需要将距离搜索与边界矩形搜索相结合。这可能有所帮助。 http://www.plumislandmedia.net/mysql/haversine-mysql-nearest-loc/

答案 1 :(得分:1)

我认为您应该将MIN()函数添加到距离计算中,以获得每个配置文件最近位置的距离。另外,按个人资料信息添加GROUP BY

(我知道MySQL允许返回不在GROUP BY中的列,但这不是我要求的,所以我从*中删除了SELECT

SELECT MIN(3959*acos(cos(radians(30.292424))*cos(radians(lat))*cos(radians(lng)-  
       radians(-97.73856))+sin(radians(30.292424))*sin(radians(lat)))) AS distance,
      `profiles`.`name` as profilename, 
      `profiles`.`profile_id` as profile_id
 FROM (`profiles`)
 JOIN `location_assignment` 
          ON `profiles`.`profile_id` =`location_assignment`.`profile_id`
 JOIN `locations` 
          ON `location_assignment`.`location_id` = `locations`.`location_id`
GROUP BY `profiles`.`name`, `profiles`.`profile_id`
HAVING `distance` < 50
ORDER BY `distance`
LIMIT 3"