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
この句は、各都市とポイントの間の大圏距離を計算する hasersine 式です。
(3959 * ACOS(COS(RADIANS(LATITUDE))
* COS(RADIANS(mylat))
* COS(RADIANS(LONGITUDE) - RADIANS(mylng))
+ SIN(RADIANS(LATITUDE))
* SIN(RADIANS(mylat))
この句を使用すると、クエリにバインドされた変数として、ポイントと半径制限を 1 回だけ入力できます。さまざまな数式でこれらの変数が複数回使用されるため、これは役に立ちます。
SELECT :LAT AS mylat,
:LONG AS mylng,
:RADIUS_LIMIT AS mydst
FROM DUAL
クエリの残りの部分は単に整理するだけなので、選択して距離で並べ替えることができます。
より完全な説明は次のとおりです。 http://www.plumislandmedia.net/mysql/haversine-mysql-nearest-loc/