4

午後、

私はこの問題に頭を悩ませるのに少し苦労しています。英国の郵便番号とその経度と緯度の値のリストを含むMySQLテーブルがあります。指定されたlong/latペアに最も近い郵便番号を見つけるテーブルで検索を実行できるようにしたいと思います。

私が使おうとしているクエリは次のとおりです。

"SELECT id, outcode AS thecode, @la := MATCH(lat) AGAINST(?) AS score_lat, @ln := MATCH(lng) AGAINST(?) AS score_lng, @la + @ln AS score_total FROM postcodes ORDER BY score_total DESC LIMIT 10

ただし、これはランダムな郵便番号のように見えるものを返すだけです。たとえば、Lat:55.775549およびLong:-4.047556

Array
(
[0] => Array
    (
        [id] => 929
        [thecode] => FK14
        [score_lat] => 0
        [score_lng] => 0
        [score_total] => 0
    )

[1] => Array
    (
        [id] => 2785
        [thecode] => UB3
        [score_lat] => 0
        [score_lng] => 0
        [score_total] => 0
    )

[2] => Array
    (
        [id] => 993
        [thecode] => G70
        [score_lat] => 0
        [score_lng] => 0
        [score_total] => 0
    )

[3] => Array
    (
        [id] => 2849
        [thecode] => WC2B
        [score_lat] => 0
        [score_lng] => 0
        [score_total] => 0
    )

[4] => Array
    (
        [id] => 1057
        [thecode] => GU29
        [score_lat] => 0
        [score_lng] => 0
        [score_total] => 0
    )

[5] => Array
    (
        [id] => 2913
        [thecode] => WS13
        [score_lat] => 0
        [score_lng] => 0
        [score_total] => 0
    )

[6] => Array
    (
        [id] => 1121
        [thecode] => HP20
        [score_lat] => 0
        [score_lng] => 0
        [score_total] => 0
    )

[7] => Array
    (
        [id] => 1185
        [thecode] => IG6
        [score_lat] => 0
        [score_lng] => 0
        [score_total] => 0
    )

[8] => Array
    (
        [id] => 1249
        [thecode] => IV25
        [score_lat] => 0
        [score_lng] => 0
        [score_total] => 0
    )

[9] => Array
    (
        [id] => 1313
        [thecode] => KA8
        [score_lat] => 0
        [score_lng] => 0
        [score_total] => 0
    )
)

データベースのスキーマは次のとおりです。

CREATE TABLE `postcodes` (
  `id` int(11) NOT NULL auto_increment,
  `outcode` varchar(4) NOT NULL,
  `lat` varchar(20) NOT NULL,
  `lng` varchar(20) NOT NULL,
  PRIMARY KEY  (`id`),
  FULLTEXT KEY `lat` (`lat`),
  FULLTEXT KEY `lng` (`lng`)
) ENGINE=MyISAM AUTO_INCREMENT=2975 DEFAULT CHARSET=latin1 AUTO_INCREMENT=2975 ;

誰かが助けてくれることを願っています!さらに詳しい情報が必要な場合は、お問い合わせください...

ありがとう、

tip2tail

4

1 に答える 1

5

MySQLMATCH()関数は、文字列を「照合」するための全文検索に使用されます。(したがって、ゼロの値を返すことは驚くべきことではありません。)

「最も近い」とは、(10進角)緯度と経度で指定された座標を使用して、マップ上の2点間の距離(「カラスが飛ぶように」測定)を計算することを意味する場合、実際に使用する必要があります。大圏距離(GCD)の計算。

http://en.wikipedia.org/wiki/Great-circle_distance

これらの厄介な詳細をすべてスキップして、私の実装を利用することができます。以下は、私のSQLステートメントの1つのSELECTリストからの抜粋です。この式は、2つのポイント間の距離(マイル単位)を計算します...

     , ACOS(
          COS(RADIANS( d2.latitude ))
        * COS(RADIANS( d1.latitude ))
        * COS(RADIANS( d2.longitude ) - RADIANS( d1.longitude ))
        + SIN(RADIANS( d2.latitude ))
        * SIN(RADIANS( d1.latitude ))
           )*3958.82 AS distance_miles

この例でd1は、は原点をd2表し、終点を表します。およびはDECIMAL値として提供されますlatitudelongitude

の「既知の」ポイントがd11つあるので、この式で順序付けて、「最も近い」ポイントをd2最初に取得できます。(複数の原点の場合d1.id、次に、この式で並べ替えて、d2それぞれに最も近いものを最初に取得できますd1。しかし、私の問題については十分です...


私はあなたの質問からクエリをコピーし、それを修正しました(以下)。基本的に、「スコア」列を削除し、距離計算を行う式に置き換えました。

SELECT id
     , outcode AS thecode
     , ACOS(
           COS(RADIANS( d2.latitude ))
         * COS(RADIANS( @d1_latitude ))
         * COS(RADIANS( d2.longitude ) - RADIANS( @d1_longitude ))
         + SIN(RADIANS( d2.latitude ))
         * SIN(RADIANS( @d1_latitude ))
           )*3958.82 AS distance_miles
  FROM postcodes d2
  JOIN (SELECT @d1_latitude := ?, @d1_longitude := ?) v
 ORDER BY distance_miles LIMIT 10

この場合、@d1_変数(バインド変数から割り当てられる)は、「既知の」ポイントの緯度と経度です。テーブルの各行(便宜上、postcodesエイリアスを作成しました)について、この式は、テーブルの緯度/経度と「既知の」ポイントとの間の距離を計算します。d2

注:インラインビューはそのままエイリアスされるvため、緯度を1回だけバインドし、参照可能なユーザー変数に値を割り当てることができます。そのインラインビューは省略でき、緯度を2回バインドする必要がある場所を確認できます。

注:これは「マイル」で距離を計算します。3958.82定数の代わりに別の値を使用すると、距離をキロメートル(km)で簡単に取得できます。

注:距離を返す必要はありません。距離順に最も近い10を返すことだけに関心がある場合は、その式をORDERBY句に入れることができます。

SELECT id
     , outcode AS thecode
  FROM postcodes d2
  JOIN (SELECT @d1_latitude := ?, @d1_longitude := ?) v
 ORDER
    BY ACOS(
           COS(RADIANS( d2.latitude ))
         * COS(RADIANS( @d1_latitude ))
         * COS(RADIANS( d2.longitude ) - RADIANS( @d1_longitude ))
         + SIN(RADIANS( d2.latitude ))
         * SIN(RADIANS( @d1_latitude ))
           )*3958.82 AS distance_miles
 LIMIT 10

2点間の距離以外のものをお探しの場合はお知らせください。その場合、この回答はまったく役に立ちません。

于 2012-08-01T19:23:32.933 に答える