MySQL计算距离(简单解决方法)

3

我有一个查询,用于获取给定距离和邮政编码内的地址。距离是根据经度和纬度数据计算出来的。

在这个例子中,我已经将用户输入替换为具体值(纬度=52.64、经度=6.88和所需距离=10公里)。

查询如下:

SELECT *,
ROUND( SQRT( POW( ( (69.1/1.61) * ('52.64' - latitude)), 2) + POW(( (53/1.61) * ('6.88' - longitude)), 2)), 1) AS distance
FROM lp_relations_addresses distance
WHERE distance < 10
 ORDER BY `distance`  DESC

错误信息显示未知列距离。

当省略where子句时,会获取表中的每条记录,包括计算出的距离。在这种情况下,必须获取整个表格。

如何仅获取所需记录?

提前感谢您的任何评论!

3个回答

6

在SQL语句的其它部分中,无法引用选择子句中的别名。您需要将整个表达式放入WHERE子句中:

WHERE
    ROUND( SQRT( POW( ( (69.1/1.61) * ('52.64' - latitude)), 2)
        + POW(( (53/1.61) * ('6.88' - longitude)), 2)), 1) < 10

更为简洁的解决方案是使用子查询生成计算数据:

  SELECT *, distance
    FROM (
       SELECT *,
           ROUND( SQRT( POW( ( (69.1/1.61) * ('52.64' - latitude)), 2)
               + POW(( (53/1.61) * ('6.88' - longitude)), 2)), 1) AS distance
           FROM lp_relations_addresses
       ) d
   WHERE d.distance < 10
ORDER BY d.distance DESC

Demo: http://www.sqlize.com/q96p2mCwnJ


谢谢!我该睡觉了:) 这个问题太容易解决了..... - Terradon
明天我会尝试您的更简洁的解决方案,并将其与Explain进行比较,再次感谢您的贡献,您的帮助为我节省了很多时间! - Terradon
@Terradon:我建议你也看一下Ilmari Karonen的解决方案,因为它可能更有效率。 - mellamokb
@mellamokb 你好,谢谢你的回答,我该如何将这个值转换为公里? - sajad abbasi

3

正如mellamokb指出的,在WHERE子句中不能引用列别名。但是,在HAVING子句中可以这样做

SELECT *,
  ROUND( SQRT( POW( ( (69.1/1.61) * ('52.64' - latitude)), 2) +
         POW(( (53/1.61) * ('6.88' - longitude)), 2)), 1) AS distance
FROM lp_relations_addresses
HAVING distance < 10
ORDER BY distance DESC

附注:如果您有大量地址,您可能需要通过尽早排除其中一些地址来优化查询。例如,使用合适的索引,以下版本可能会更快:

SELECT *,
  ROUND( SQRT( POW( ( (69.1/1.61) * ('52.64' - latitude)), 2) +
         POW(( (53/1.61) * ('6.88' - longitude)), 2)), 1) AS distance
FROM lp_relations_addresses
WHERE latitude > '52.64' - 10 / (69.1/1.61)
  AND latitude < '52.64' + 10 / (69.1/1.61)
  AND longitude > '6.88' - 10 / (53/1.61)
  AND longitude < '6.88' + 10 / (53/1.61)
HAVING distance < 10
ORDER BY distance DESC

尽管你需要在HAVING子句之后加上ORDER BY子句,但这样它就能很好地运行了:http://www.sqlize.com/7e8TpPqiuj。 - mellamokb
感谢大家的贡献!这让我省了不少麻烦。 - Terradon

2

您将计算结果命名为“distance”,但是您还将表“lp_relations_addresses”命名为“distance”。尝试使用不同的名称,如下所示:

SELECT *,
ROUND( SQRT( POW( ( (69.1/1.61) * ('52.64' - latitude)), 2) + POW(( (53/1.61) * ('6.88' - longitude)), 2)), 1) AS distance
FROM lp_relations_addresses addr
WHERE distance < 10
ORDER BY `distance`  DESC

我也尝试了你的代码,但是where子句中的distance给出了未知列距离的错误。 - Terradon
在表别名冲突方面,你发现得很好,但正如mellamokb所指出的那样,在where语句中不能使用别名,但是可以像Ilmari所说的那样在having语句中使用... - StuartLC

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接