2011-09-21 8 views
1

したがって、緯度、経度、および半径パラメータに基づいて最寄りの都市を計算するこの機能があります。都市表からのジオロケーション距離SQL

DELIMITER $$ 
DROP PROCEDURE IF EXISTS `world_db`.`geolocate_close_cities`$$ 
CREATE PROCEDURE `geolocate_close_cities`(IN p_latitude DECIMAL(8,2), p_longitude DECIMAL(8,2), IN p_radius INTEGER(5)) 
BEGIN 
     SELECT id, country_id, longitude, latitude, city, 
     truncate((degrees(acos(sin(radians(latitude)) 
     * sin(radians(p_latitude)) 
     + cos(radians(latitude)) 
     * cos(radians(p_latitude)) 
     * cos(radians(p_longitude - longitude)))) 
     * 69.09*1.6),1) as distance 
     FROM cities 
     HAVING distance < p_radius 
     ORDER BY distance desc; 
    END$$ 

DELIMITER ; 

ここに私の都市テーブルの構造です:

> +------------+-------------+------+-----+---------+----------------+ | 
> Field  | Type  | Null | Key | Default | Extra   | 
> +------------+-------------+------+-----+---------+----------------+ | 
> id   | int(11)  | NO | PRI | NULL | auto_increment | | 
> country_id | smallint(6) | NO |  | NULL |    | | 
> region_id | smallint(6) | NO |  | NULL |    | | 
> city  | varchar(45) | NO |  | NULL |    | | 
> latitude | float  | NO |  | NULL |    | | 
> longitude | float  | NO |  | NULL |    | | 
> timezone | varchar(10) | NO |  | NULL |    | | 
> dma_id  | smallint(6) | YES |  | NULL |    | | 
> code  | varchar(4) | YES |  | NULL |    | 
> +------------+-------------+------+-----+---------+----------------+ 

それは非常によく動作します。私は(pseudcode)を行うためにLKE思い何

のようなものです:

SELECT * FROM cities WHERE DISTANCE(SELECT id FROM cities WHERE id={cityId}, {km)) 

、それは私に最も近い都市を返します。

どうすればいいですか?

現時点では、関数を呼び出した後、IDを繰り返し配列に渡してから、都市テーブルでWHEREINを実行しますが、これは明らかに効率的ではありません。

何か助けが大歓迎です。ありがとう。

答えて

1

あなたの都市とあなたの地位の間の最大距離を制限することができる場合は、1分の緯度(南北)が1海里であるという事実を利用してください。

緯度表にインデックスを挿入します。

あなたの質問に表示されているhaversineの数式からhaversine(lat1、lat2、long1、long2、unit)の関数を作成してください。以下を参照してください

これを行うには、mylatitude、mylongitude、およびmykmを指定します。

SELECT * 
    from cities a 
where :mylatitude >= a.latitude - :mykm/111.12 
    and :mylatitude <= a.latitude + :mykm/111.12 
    and haversine(:mylatitude,a.latitude,:mylongitude,a.longitude, 'KM') <= :mykm 
order by haversine(:mylatitude,a.latitude,:mylongitude,a.longitude, 'KM') 

これは粗雑に離れすぎてあなたのポイントからある都市を除外するために緯度のバウンディングボックスを使用します。あなたのDBMSはあなたの緯度指数でインデックス範囲のスキャンを使用して、考慮する価値があるあなたの都市テーブルの行を素早く選ぶでしょう。それからあなたのhaversine関数、すべての正弦と余弦の数学を持つもの、それらの行だけを実行します。

経度の地上距離が緯度によって異なるため、私は緯度を推奨します。

これは粗いことに注意してください。それは店のファインダーにとっては大丈夫ですが、あなたが土木技術者であればそれを使用しないでください。地球は楕円形をしており、これは円形であると想定しています。

(111.12マジックナンバーについては申し訳ありません。それは緯度の度にキロ数ですが、それは60海里である。)


は、実行可能な距離関数についてはこちらを参照してください。

Why does this MySQL stored function give different results than to doing the calculation in the query?

+0

こんにちは@Ollie Jones。あなたの迅速な対応をありがとうございました。正直言って、私はあなたのSQLが何をするかに合わせて私の関数を変更する方法を完全に理解しているとは思えません。ありがとう! :-) – Flukey

+0

私は半正矢式をcreatedeは、ここに私のクエリです:cities_tempから 'SELECT * どこ52.205> = a.latitude - 100/111.12 と52.205 <= a.latitude + 100/111.12 と半正矢(52.205、 (52.205、a.latitude、0.144、a.longitude、 'KM') 'ここで、緯度は52.205、経度は0.144(緯度は0.144、緯度は0.144、緯度は 'KM')<= 100 ケンブリッジ、英国) – Flukey

0

this other questionをご覧ください。これは助けになるはずです。

+0

これはどのように機能しますか? :-) – Flukey

+0

lat、long、およびdistanceは渡されるparamsです。正確ではありませんが、まともな見積もりでなければなりません。どの程度正確にする必要がありますか? –

+0

「時間的に正確」ではない。ユーザーが「自分のエリア内のユーザー」をクリックしたとき。彼らはラジオを選択することができますし、それらの近くに都市をフィルタリングします。注:現在、それはかなり正確です。もちろん、いくつかは数キロメートルになりますが、これは大きな問題ではありません。確かに、より正確な方がより正確です!しかし、私も効率が欲しいです。 – Flukey

関連する問題