根据每个作业的最低距离获取单个对应的行

时间:2014-01-07 23:36:52

标签: mysql sql sorting group-by

我正在建立一个系统,用户可以使用邮政编码进行搜索(很快就会有多个邮政编码),每个“工作”最多可以有三个不同的位置。我需要返回最低距离作业的ID,以及计算的距离和作业的所有其他字段。

我可以计算工作的距离。我甚至可以为每份工作返回一个结果。

但我无法返回每个作业的最低距离结果。

我在这里整理了一个SQL小提琴:http://sqlfiddle.com/#!2/03b2c/10

示例数据:

输入:SET @user_lat = 44.053575, @user_lng = -123.086493, @range = 50;

ID  JOB_ID  LATITUDE    LONGITUDE               DISTANCE

9   1       44.063716888428 -123.08470916748    0
8   1       44.052070617676 -123.086753845215   0.81
7   1       44.035049438477 -123.047355651855   2.71

10  2       44.059913635254 -123.017936706543   3.32
11  2       44.045707702637 -122.930877685547   7.73
13  3       45.480751037598 -122.642738342285   100.21

小组结果 - 每行都可以,但不是最近的距离。

ID  JOB_ID  LATITUDE        LONGITUDE           DISTANCE
7   1       44.035049438477 -123.047355651855   2.71
10  2       44.059913635254 -123.017936706543   7.73

ROUND( [math], 2 ) AS distance -- (full query below)
...
GROUP BY job_id

HAVING distance < @range

ORDER BY distance ASC;

GROUP和Min()结果: - 正确返回最低距离,但没有正确的ID。

ID  JOB_ID  LATITUDE        LONGITUDE           DISTANCE
7   1       44.035049438477 -123.047355651855   0
10  2       44.059913635254 -123.017936706543   3.32

MIN( ROUND( [math], 2 ) ) AS distance
...
GROUP BY job_id

HAVING distance < @range

ORDER BY distance ASC;

__

我需要的是: - 返回最低距离,ID与该距离匹配。

ID  JOB_ID  LATITUDE        LONGITUDE           DISTANCE
9   1       44.035049438477 -123.047355651855   0
11  2       44.059913635254 -123.017936706543   3.32

__

完整查询群组结果示例

set
  @user_lat = 44.063717, 
  @user_lng = -123.084706,
  @range = 2000;


-- Filter by distance, displaying the nearest location of each job in miles
select 
  *,

  -- We can use min() here to get the lowest distance, but this does not affect the ID returned!
  -- min( ... ) as distance

  ROUND(3956 * 2 * ASIN(SQRT(POWER(SIN( (@user_lat - abs(loc.latitude))  * pi()/180 / 2),2) + COS(@user_lat * pi()/180 ) * COS( abs(loc.latitude) * pi()/180) * POWER(SIN((@user_lng - loc.longitude) * pi()/180 / 2), 2) )), 2)
    as distance

from `locations` loc

group by job_id

having distance < @range

order by distance asc;

2 个答案:

答案 0 :(得分:2)

因为它是mysql,你可以利用它的特殊分组实现,从而得到一个非常简单的查询:

select * from (
  select *,
  ROUND(3956 * 2 * ASIN(SQRT(POWER(SIN( (@user_lat - abs(loc.latitude))  * pi()/180 / 2),2) + COS(@user_lat * pi()/180 ) * COS( abs(loc.latitude) * pi()/180) * POWER(SIN((@user_lng - loc.longitude) * pi()/180 / 2), 2) )), 2) as distance
  from locations
  order by distance) loc
group by job_id

答案 1 :(得分:1)

我暂时忽略了范围...

如果distance()是一个函数(很容易构造这样的东西)那么查询可能看起来像这样......

SELECT x.*
     , distance(x.latitude,x.longitude,@user_lat,@user_lng)
  FROM 
     ( SELECT job_id
            , MIN(distance(latitude,longitude,@user_lat,@user_lng)) min_distance 
         FROM locations 
        GROUP 
           BY job_id
     ) y
    ON job_id = x.job_id
   AND y.min_distance = distance(x.latitude,x.longitude,@user_lat,@user_lng);