2011-11-10 81 views
-1

首次发布时,我会尽量遵守最佳做法。对MySQL列数据进行分组

我试图构建一个用于测量用户位置的MySQL查询(分别表示为纬度和经度为$Lat$Lng的查询)。查询应该返回距离用户最近的50个电台。

问题是我的表中的数据包含每个站的位置入口每个站我只需要每个站最近的站入口!

这是我的查询:

SELECT id, lat, lng, station_name, routes, 
    (3959 * acos(cos(radians($Lat)) 
    * cos(radians(lat)) * cos(radians(lng) - 
    radians($Lng)) + sin(radians($Lat)) * sin(radians(lat)))) AS distance 
FROM subway_stations ORDER BY distance LIMIT 0 , 50; 

上述MySQL查询完成以下操作:

  1. 选择从ID,纬度,经度,站的班次数据和路线
  2. 测量每个站点的lat和lng与用户的数据 - 将该数据存储为'distance'
  3. 返回50个最近的结果

我需要组这些结果在一起,使得每个站只有一个记录被返回,所述一个随着距离列中的最低值,这是最接近用户站入口。

我试过使用GROUP BY但我似乎正在实施它不正确,因为返回的结果不是所需的。

回答

0

很难知道没有建立样本数据库,但我怀疑你想要做如下修改:

  1. 添加group by station_name, id, lat, lng到您的查询的末尾

  2. 所有select不属于group by子句的字段需要一个聚合函数。最明显的是,distance应该需要一个min(...)

  3. 我不知道是否可以使用orderlimit条款。如果你有问题,把它们拿出来(暂时),让这个工作很多。为了方便起见,请调用此查询Q1。

  4. 如果order bylimit子句不能使用(实验,观察),那么你要嵌套查询。这看起来像select * from (...Q1...) t1 ORDER BY distance LIMIT 0,50t1为内部选择分配了一个临时名称,在该查询中没有实际使用,但是语法是必需的。

  5. 作为优化,您可能希望将having子句添加到内部Q1查询中。也就是说,如果您知道边界距离,请添加HAVING distance<XXXXX

注意步骤3 - 5可能不需要,我不知道第3步

+0

如果您向查询添加了“group by station_name,id,lat,lng”,它基本上与根本不分组相同。 –

+0

我假设'station_name'唯一定义了'id','lat','lng','id'作为可能的主键。但重读原来的问题,似乎'id'可能是指个人入口。所以你可能是对的。我正在重新考虑。 – Pursuit

+0

@Sam看起来你的回答是正确的。你只需要添加'order by'和'limit'子句来回答原来的问题。 (我的名声还不够高,无法对你的问题发表评论)。 – Pursuit

0

如果你只需要为每个站一个最小的记录,你不需要LIMIT .. 只是做

$result = mysql_query("SELECT id, lat, lng, station_name, routes, MIN(
    (3959 * acos(cos(radians($Lat)) * cos(radians(lat)) * 
    cos(radians(lng) - radians($Lng)) + sin(radians($Lat)) * 
    sin(radians(lat)))) AS distance) 
FROM subway_stations 
GROUP BY station_name; 

这将返回每个站只有一条记录与最小距离。

+0

这不起作用。当您选择'GROUP BY'子句中未指定的字段时,结果是未定义的 - 您将从任意行获得结果。 –

0

你可能有更容易得到每个站用PHP最接近入口。

这实际上是一个常见问题,您需要使用子查询来解决这个问题。 我假设id只是一个行ID,并不是每个电台唯一的。

SELECT subway_stations.* FROM (
    SELECT station_name, MIN(
     (3959 * acos(cos(radians($Lat)) * cos(radians(lat)) * 
     cos(radians(lng) - radians($Lng)) + sin(radians($Lat)) * 
     sin(radians(lat)))) 
    ) AS distance 
    FROM subway_stations 
    GROUP BY station_name 
) AS min_distances 
JOIN subway_stations ON (
    min_distances.station_name = subway_stations.station_name 
    AND (3959 * acos(cos(radians($Lat)) * cos(radians(lat)) * 
     cos(radians(lng) - radians($Lng)) + sin(radians($Lat)) * 
     sin(radians(lat))) 
    ) = min_distances.distance 
) 

这是针对您的问题的典型“纯粹mysql”解决方案。但是,由于计算距离的计算程度,您可能希望: - 使用您的初始查询,并使用php获取每个工作站的最短距离或运行上面的内部查询,但插入其结果转换为临时表,然后执行上述查询的等效操作,但将计算的距离替换为距离临时表的计算距离。