您对 mySQL 距离搜索有很好的参考。
忘记 Oracle Spatial 的东西。太多的代码,太多的复杂性,没有足够的附加值。
这是一个可以解决问题的查询。这使用法定英里的距离。 编辑这修复了 mdarwin 提到的错误,如果您尝试将它用于北极或南极的位置,则需要进行除法检查。
SELECT id, city, LATITUDE, LONGITUDE, distance
FROM
(
SELECT id,
city,
LATITUDE, LONGITUDE,
(3959 * ACOS(COS(RADIANS(LATITUDE))
* COS(RADIANS(mylat))
* COS(RADIANS(LONGITUDE) - RADIANS(mylng))
+ SIN(RADIANS(LATITUDE))
* SIN(RADIANS(mylat))
))
AS distance,
b.mydst
FROM Cities
JOIN (
SELECT :LAT AS mylat,
:LONG AS mylng,
:RADIUS_LIMIT AS mydst
FROM DUAL
)b ON (1 = 1)
WHERE LATITUDE >= mylat -(mydst/69)
AND LATITUDE <= mylat +(mydst/69)
AND LONGITUDE >= mylng -(mydst/(69 * COS(RADIANS(mylat))))
AND LONGITUDE <= mylng +(mydst/(69 * COS(RADIANS(mylat))))
)a
WHERE distance <= mydst
ORDER BY distance
如果您以公里为单位,请将 mydst/69 更改为 mydst/111.045,并将 3959 更改为 6371.4。(1/69 将英里转换为度;3959 是行星半径的值。)
现在,您可能很想将这个大查询用作“魔法黑匣子”。不要这样做!这不是很难理解,如果你理解它,你将能够做得更好。这是正在发生的事情。
该子句是使查询快速的核心。它会在您的 Cities 表中搜索您指定的附近城市。
WHERE LATITUDE >= mylat -(mydst/69)
AND LATITUDE <= mylat +(mydst/69)
AND LONGITUDE >= mylng -(mydst/(69 * COS(RADIANS(mylat))))
AND LONGITUDE <= mylng +(mydst/(69 * COS(RADIANS(mylat))))
要使其正常工作,您肯定需要在 LATITUDE 列上建立索引。LONGITUDE 列上的索引也会有所帮助。它会进行近似搜索,查找位于您的点附近地球表面的准矩形斑块内的行。它选择了太多的城市,但不是太多。
此处的此子句可让您从结果集中消除额外的城市:
WHERE distance <= mydst
该子句是计算每个城市与您的点之间的大圆距离的haversine 公式。
(3959 * ACOS(COS(RADIANS(LATITUDE))
* COS(RADIANS(mylat))
* COS(RADIANS(LONGITUDE) - RADIANS(mylng))
+ SIN(RADIANS(LATITUDE))
* SIN(RADIANS(mylat))
此子句允许您输入点和半径限制,作为查询的绑定变量一次。这很有帮助,因为各种公式多次使用这些变量。
SELECT :LAT AS mylat,
:LONG AS mylng,
:RADIUS_LIMIT AS mydst
FROM DUAL
查询的其余部分只是简单地组织事物,以便您按距离进行选择和排序。
这是一个更完整的解释:http ://www.plumislandmedia.net/mysql/haversine-mysql-nearest-loc/