对于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
该子句是用于计算每个城市与您的观点之间的大圆距离的半正公式.
(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
查询的其余部分只是组织事物,以便您按距离选择和排序.