17

私は持ってい$latitude = 29.6815400$longitude = 64.3647100、今MySQLで、これらの座標に最も近い15の場所を取得したいと思います。そして、このクエリを実行することを計画しています。

SELECT *
FROM places
WHERE latitude  BETWEEN($latitude  - 1, $latitude  + 1)
AND   longitude BETWEEN($longitude - 1, $logintude + 1)
LIMIT 15;

あなたはそれが正しいと思いますか、それとも何か他のものを提案しますか?

BEETWEEN近くの場所で最大50Kmの範囲を検索したいので、どうすればよいですか?

クエリを実行する前に、PHPを使用して何でもできると言うのを忘れました。

注:ストアドプロシージャは使用できません

4

4 に答える 4

19

2点間の距離を計算するためのPHPの式は次のとおりです。

function getDistanceBetweenPointsNew($latitude1, $longitude1, $latitude2, $longitude2, $unit = 'Mi') 
{
   $theta = $longitude1 - $longitude2;
   $distance = (sin(deg2rad($latitude1)) * sin(deg2rad($latitude2))+
               (cos(deg2rad($latitude1)) * cos(deg2rad($latitude2)) * cos(deg2rad($theta)));
   $distance = acos($distance); $distance = rad2deg($distance); 
   $distance = $distance * 60 * 1.1515;

   switch($unit) 
   { 
     case 'Mi': break;
     case 'Km' : $distance = $distance * 1.609344; 
   } 
   return (round($distance,2)); 
}

次に、クエリを追加して、距離が上記のレコード以下のすべてのレコードを取得します。

$qry = "SELECT * 
        FROM (SELECT *, (((acos(sin((".$latitude."*pi()/180)) *
        sin((`geo_latitude`*pi()/180))+cos((".$latitude."*pi()/180)) *
        cos((`geo_latitude`*pi()/180)) * cos(((".$longitude."-
        `geo_longitude`)*pi()/180))))*180/pi())*60*1.1515*1.609344) 
        as distance
        FROM `ci_geo`)myTable 
        WHERE distance <= ".$distance." 
        LIMIT 15";

同様の計算については、こちらをご覧ください。

そして、あなたはここでもっと読むことができます

アップデート:

経度2経度2を計算するには、次のことを知っておく必要があることに注意する必要があります。

緯度は約69マイル(111キロメートル)離れています。範囲は(地球のわずかな楕円形のために)赤道での68.703マイル(110.567 km)から極での69.407(111.699 km)まで変化します。これは、1分(1/60度)が約1マイルであるため便利です。

経度の程度は、 69.172マイル(111.321)の赤道で最も広く、極で徐々にゼロに縮小します。北緯40度または南緯40度では、経度間の距離は53マイル(85 km)です。

$longitude2 $latitude2したがって、50kmに従って計算すると、およそ次のようになります。

$longitude2 = $longitude1 + 0.449; //0.449 = 50km/111.321km
$latitude2 = $latitude1 + 0.450; // 0.450 = 50km/111km
于 2013-01-10T10:07:34.877 に答える
17

MySQL のような DBMS を大量のクエリでフラッディングすることは、最善の解決策ではないことを考慮する必要があります。

$radius代わりに、完全な円の半径を突然選択する代わりに、side の単純な正方形内の座標を持つすべての場所を選択する非常に高速な SQL クエリを推測できます。PHP余剰分をフィルタリングできます。

概念を示しましょう:

$lat    = 45.0.6072;
$lon    = 7.65678;
$radius = 50; // Km

 // Every lat|lon degree° is ~ 111Km
$angle_radius = $radius / ( 111 * cos( $lat ) );

$min_lat = $lat - $angle_radius;
$max_lat = $lat + $angle_radius;
$min_lon = $lon - $angle_radius;
$max_lon = $lon + $angle_radius;

$results = $db->getResults("... WHERE latitude BETWEEN $min_lat AND $max_lat AND longitude BETWEEN $min_lon AND $max_lon"); // your own function that return your results (please sanitize your variables)

$filtereds = [];
foreach( $results as $result ) {
    if( getDistanceBetweenPointsNew( $lat, $lon, $result->latitude, $result->longitude, 'Km' ) <= $radius ) {
        // This is in "perfect" circle radius. Strip it out.
        $filtereds[] = $result;
    }
}

// Now do something with your result set
var_dump( $filtereds );

このように、MySQL は完全なテーブル スキャンを必要としない非常に使いやすいクエリを実行しますが、PHPgetDistanceBetweenPointsNew()はこのページに掲載されている関数と同様のものを使用して余剰を取り除き、結果セットの座標から半径の中心までの距離を比較します。 .

(大きな) パフォーマンスの向上を無駄にしないために、データベース内の座標列にインデックスを付けます。

ハッピーハッキング!

于 2015-03-03T21:36:42.177 に答える
2

特定のポイントからの距離で注文し、これをSQL selectステートメントに配置して、住宅販売アプリで同様のことを行いました。

((ACOS(SIN(' . **$search_location['lat']** . ' * PI() / 180) * SIN(**map_lat** * PI() / 180) + COS(' . **$search_location['lat']** . ' * PI() / 180) * COS(**map_lat** * PI() / 180) * COS((' . **$search_location['lng']** . ' - **map_lng**) * PI() / 180)) * 180 / PI()) * 60 * 1.1515) AS "distance"

関連する lat/lng 値に置き換え$search_locationます。map_lat/map_lng 値は、lat/lng 値を含む SQL 列です。結果を距離で並べ替え、where または having 句を使用して 50 km の範囲内のプロパティをフィルター処理できます。

ページングなどの追加機能が必要な場合は、PHP と比較して SQL をアプローチとして使用することをお勧めします。

于 2013-01-10T14:03:38.967 に答える