我正在尝试执行距离计算以返回特定距离内的地点列表。这是基于使用邮政编码数据库并确定从原点到每个位置的距离。我想要做的是将结果限制在离原点一定距离之内,但我的MySQL查询有问题。这是基本查询:
SELECT *,
ROUND(DEGREES(ACOS(SIN(RADIANS(42.320271)) * SIN(RADIANS(zip_latitude)) + COS(RADIANS(42.320271)) * COS(RADIANS(zip_latitude)) * COS(RADIANS(-88.462832 - zip_longitude))))) * 69.09 AS distance
FROM locations
LEFT JOIN zip_codes USING (zip_code)
ORDER BY distance ASC
这很好用,并为我提供了每个位置的所有信息,包括与原始邮政编码的距离......正是我想要的。但是,我想将结果限制在一定距离内(即,距离<= 50)。
我的问题和问题是我无法弄清楚在上面的查询中包含(WHERE距离&lt; = 50)以使其全部工作。我尝试的一切都给了我一个错误信息。任何帮助都会很棒。
答案 0 :(得分:1)
您有两种选择:
重写WHERE子句中的逻辑,以便您可以按它进行过滤:
SELECT *,
ROUND(DEGREES(ACOS(SIN(RADIANS(42.320271)) * SIN(RADIANS(zip_latitude)) + COS(RADIANS(42.320271)) * COS(RADIANS(zip_latitude)) * COS(RADIANS(-88.462832 - zip_longitude))))) * 69.09 AS distance
FROM locations
LEFT JOIN zip_codes USING (zip_code)
WHERE (ROUND(DEGREES(ACOS(SIN(RADIANS(42.320271)) * SIN(RADIANS(zip_latitude)) + COS(RADIANS(42.320271)) * COS(RADIANS(zip_latitude)) * COS(RADIANS(-88.462832 - zip_longitude))))) * 69.09) <= 50
ORDER BY distance
这是更好的选择,因为它只需要传递一次数据。遗憾的是,它需要您复制逻辑 - 如果您使用的是GROUP BY
或HAVING
子句中的信息,MySQL支持在这些中引用列别名。
使用子查询:
SELECT x.*
FROM (SELECT *,
ROUND(DEGREES(ACOS(SIN(RADIANS(42.320271)) * SIN(RADIANS(zip_latitude)) + COS(RADIANS(42.320271)) * COS(RADIANS(zip_latitude)) * COS(RADIANS(-88.462832 - zip_longitude))))) * 69.09 AS distance
FROM locations
LEFT JOIN zip_codes USING (zip_code)) x
WHERE x.distance <= 50
ORDER BY x.distance
答案 1 :(得分:0)
一个简单的解决方案是将查询包装在另一个查询中,并将条件和顺序放在那里。这应该有效:
SELECT * FROM (
SELECT *, ROUND(DEGREES(ACOS(SIN(RADIANS(42.320271)) * SIN(RADIANS(zip_latitude)) + COS(RADIANS(42.320271)) * COS(RADIANS(zip_latitude)) * COS(RADIANS(-88.462832 - zip_longitude))))) * 69.09 AS distance FROM locations LEFT JOIN zip_codes USING (zip_code)
) WHERE distance <= 50 ORDER BY distance ASC
中间一行是没有ORDER BY
答案 2 :(得分:0)
最简单的解决方案实际上是使用HAVING而不是WHERE,我也将ROUND函数的最后一个括号移到了69.09后面,这样可以提高计算精度,但仍然会返回一个舍入数字:
SELECT *,
ROUND(DEGREES(ACOS(SIN(RADIANS(42.320271)) * SIN(RADIANS(zip_latitude))
+ COS(RADIANS(42.320271)) * COS(RADIANS(zip_latitude))
* COS(RADIANS(-88.462832 - zip_longitude)))) * 69.09,2) AS distance
FROM locations
LEFT JOIN zip_codes USING (zip_code)
HAVING distance <= 50
ORDER BY distance ASC
所以基本上你的查询很好,你只需要添加HAVING子句,你可能想要修复该舍入以获得更好的结果。在我的项目中,我使用了非常相似的公式,丢弃外部DEGREES函数并乘以地球周长:
ROUND(ACOS(SIN(RADIANS('42.320271')) * SIN(RADIANS(zip_latitude))
+ COS(RADIANS('42.320271')) * COS(RADIANS(zip_latitude))
* COS(RADIANS(zip_longitude - '-88.462832'))) * 3963.190592,3) AS distance
并且通过更改末尾的乘数,你有公里而不是里程:
ROUND(ACOS(SIN(RADIANS('42.320271')) * SIN(RADIANS(zip_latitude))
+ COS(RADIANS('42.320271')) * COS(RADIANS(zip_latitude))
* COS(RADIANS(zip_longitude - '-88.462832'))) * 6378.137,3) AS distance