mySQL距離検索についてはかなり良いリファレンスがあります。
OracleSpatialのものは忘れてください。コードが多すぎる、複雑すぎる、付加価値が十分でない。
これがトリックを行うクエリです。これは、法定マイル単位の距離を使用します。 編集 これにより、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))
この句を使用すると、クエリへのバインドされた変数として、ポイントと半径制限を1回だけ入力できます。さまざまな数式でこれらの変数が複数回使用されるため、便利です。
SELECT :LAT AS mylat,
:LONG AS mylng,
:RADIUS_LIMIT AS mydst
FROM DUAL
クエリの残りの部分は単純に整理されているため、距離で選択して並べ替えることができます。
より完全な説明は次のとおりです。