Cara Tercepat untuk Menemukan Jarak Antara Dua Titik Lat / Panjang


227

Saat ini saya memiliki kurang dari satu juta lokasi dalam database mysql semuanya dengan informasi garis bujur dan garis lintang.

Saya mencoba menemukan jarak antara satu titik dan banyak titik lainnya melalui kueri. Ini tidak secepat yang saya inginkan terutama dengan 100+ hit per detik.

Apakah ada permintaan yang lebih cepat atau mungkin sistem yang lebih cepat selain mysql untuk ini? Saya menggunakan kueri ini:

SELECT 
  name, 
   ( 3959 * acos( cos( radians(42.290763) ) * cos( radians( locations.lat ) ) 
   * cos( radians(locations.lng) - radians(-71.35368)) + sin(radians(42.290763)) 
   * sin( radians(locations.lat)))) AS distance 
FROM locations 
WHERE active = 1 
HAVING distance < 10 
ORDER BY distance;

Catatan: Jarak yang disediakan adalah dalam Mil . Jika Anda membutuhkan Kilometer , gunakan 6371sebagai ganti 3959.


31
Formula yang Anda berikan tampaknya memiliki banyak elemen yang konstan. Apakah mungkin untuk melakukan pra-komputasi data dan menyimpan nilai-nilai itu juga di DB Anda? Misalnya 3959 * acos (cos (radian (42,290763)) adalah konstan tetapi memiliki 4 perhitungan utama di dalamnya Sebaliknya bisa Anda hanya menyimpan 6696,7837.?
Peter M

1
Atau setidaknya konstanta pra-komputasi di luar kueri? Itu akan mengurangi pekerjaan yang harus dilakukan.
Peter M

2
@ Peter M Sepertinya database SQL yang layak akan dioptimalkan sehingga hanya dihitung sekali.
mhenry1384

25
Bagi mereka yang bertanya-tanya, 42.290763 adalah garis lintang dan -71.35368 adalah garis bujur dari titik yang digunakan untuk menghitung jarak.
user276648

14
Sekadar info, Jarak yang dihitung dengan rumus ini adalah dalam mil, bukan dalam kilometer. Harap Ganti 3959 hingga 6371 untuk mendapatkan hasil dalam kilometer
Sahil

Jawaban:


115
  • Buat poin Anda menggunakan Pointnilai Geometrytipe data dalam MyISAMtabel. Pada Mysql 5.7.5, InnoDBtabel sekarang juga mendukung SPATIALindeks.

  • Buat SPATIALindeks pada titik-titik ini

  • Gunakan MBRContains()untuk menemukan nilai:

    SELECT  *
    FROM    table
    WHERE   MBRContains(LineFromText(CONCAT(
            '('
            , @lon + 10 / ( 111.1 / cos(RADIANS(@lon)))
            , ' '
            , @lat + 10 / 111.1
            , ','
            , @lon - 10 / ( 111.1 / cos(RADIANS(@lat)))
            , ' '
            , @lat - 10 / 111.1 
            , ')' )
            ,mypoint)

, atau, di dalam MySQL 5.1dan di atas:

    SELECT  *
    FROM    table
    WHERE   MBRContains
                    (
                    LineString
                            (
                            Point (
                                    @lon + 10 / ( 111.1 / COS(RADIANS(@lat))),
                                    @lat + 10 / 111.1
                                  ),
                            Point (
                                    @lon - 10 / ( 111.1 / COS(RADIANS(@lat))),
                                    @lat - 10 / 111.1
                                  ) 
                            ),
                    mypoint
                    )

Ini akan memilih semua titik kira-kira di dalam kotak (@lat +/- 10 km, @lon +/- 10km).

Ini sebenarnya bukan kotak, tetapi persegi panjang bulat: garis lintang dan garis bujur terikat bola. Ini mungkin berbeda dari persegi panjang polos di Tanah Franz Joseph , tetapi cukup dekat dengan itu di tempat-tempat yang paling dihuni.

  • Terapkan penyaringan tambahan untuk memilih semua yang ada di dalam lingkaran (bukan persegi)

  • Mungkin menerapkan penyaringan halus tambahan untuk memperhitungkan jarak lingkaran besar (untuk jarak besar)


15
@Quassnoi: Beberapa koreksi: Anda mungkin ingin mengubah urutan koordinat ke lat, panjang. Juga, jarak memanjang sebanding dengan kosinus garis lintang , bukan garis bujur. Dan Anda ingin mengubahnya dari multiplikasi ke divisi, sehingga koordinat pertama Anda akan dikoreksi sebagai @lon - 10 / ( 111.1 / cos(@lat))(dan menjadi yang kedua dalam pasangan setelah semuanya benar
M. Dave Auayan

8
PERINGATAN : Isi jawaban TIDAK diedit sesuai dengan komentar yang sangat valid dari @M. Dave Auayan. Catatan lebih lanjut: Metode ini menjadi pearshaped jika lingkaran bunga (a) termasuk kutub atau (b) berpotongan dengan garis bujur +/- 180 derajat bujur. Juga menggunakan cos(lon)akurat hanya untuk jarak yang lebih kecil. Lihat janmatuschek.de/LatitudeLongitudeBoundingCoordinates
John Machin

3
Apakah ada cara agar kita bisa mendapatkan beberapa wawasan tentang apa yang konstanta (10, 111.11, @lat, @lon, mypoint) mewakili? Saya berasumsi bahwa 10 adalah untuk jarak kilometer, @lat dan @lon mewakili lattitue dan bujur yang disediakan, tetapi apa yang mewakili 111.11 dan mypoint dalam contoh?
ashays

4
@ashays: kira-kira 111.(1)km dalam derajat garis lintang. mypointadalah bidang dalam tabel yang menyimpan koordinat.
Quassnoi

1
Koreksi kesalahan lain - Anda kehilangan penutupan) pada kedua ke baris terakhir
ina

100

Bukan jawaban spesifik MySql, tetapi itu akan meningkatkan kinerja pernyataan sql Anda.

Apa yang Anda lakukan secara efektif adalah menghitung jarak ke setiap titik dalam tabel, untuk melihat apakah jaraknya dalam 10 unit dari titik tertentu.

Apa yang dapat Anda lakukan sebelum Anda menjalankan sql ini, adalah membuat empat poin yang menarik kotak 20 unit di samping, dengan titik Anda di tengah yaitu. (x1, y1). . . (x4, y4), di mana (x1, y1) adalah (diberikan + 10 unit, diberikanLat + 10 unit). . . (diberikan Panjang - 10 unit, diberikanLat -10 unit). Sebenarnya, Anda hanya perlu dua poin, kiri atas dan kanan bawah memanggil mereka (X1, Y1) dan (X2, Y2)

Sekarang pernyataan SQL Anda menggunakan titik-titik ini untuk mengecualikan baris yang pasti lebih dari 10u dari titik yang Anda berikan, dapat menggunakan indeks pada garis lintang & bujur, sehingga akan menjadi urutan besarnya lebih cepat dari apa yang Anda miliki saat ini.

misalnya

select . . . 
where locations.lat between X1 and X2 
and   locations.Long between y1 and y2;

Pendekatan kotak dapat mengembalikan positif palsu (Anda dapat mengambil poin di sudut-sudut kotak yang> 10u dari titik yang diberikan), jadi Anda masih perlu menghitung jarak setiap titik. Namun ini lagi akan jauh lebih cepat karena Anda secara drastis membatasi jumlah poin untuk menguji poin dalam kotak.

Saya menyebut teknik ini "Berpikir di dalam kotak" :)

EDIT: Bisakah ini dimasukkan ke dalam satu pernyataan SQL?

Saya tidak tahu apa yang bisa dilakukan mySql atau Php, maaf. Saya tidak tahu di mana tempat terbaik adalah untuk membangun empat poin, atau bagaimana mereka dapat diteruskan ke permintaan mySql di Php. Namun, begitu Anda memiliki empat poin, tidak ada yang menghentikan Anda menggabungkan pernyataan SQL Anda sendiri dengan milik saya.

select name, 
       ( 3959 * acos( cos( radians(42.290763) ) 
              * cos( radians( locations.lat ) ) 
              * cos( radians( locations.lng ) - radians(-71.35368) ) 
              + sin( radians(42.290763) ) 
              * sin( radians( locations.lat ) ) ) ) AS distance 
from locations 
where active = 1 
and locations.lat between X1 and X2 
and locations.Long between y1 and y2
having distance < 10 ORDER BY distance;

Saya tahu dengan MS SQL saya dapat membangun pernyataan SQL yang menyatakan empat float (X1, Y1, X2, Y2) dan menghitungnya sebelum pernyataan pilih "utama", seperti saya katakan, saya tidak tahu apakah ini dapat dilakukan dengan MySql. Namun saya masih cenderung untuk membangun empat poin dalam C # dan meneruskannya sebagai parameter ke query SQL.

Maaf saya tidak bisa membantu, jika ada yang bisa menjawab bagian spesifik MySQL & Php ini, silakan edit jawaban ini untuk melakukannya.


4
Anda dapat menemukan prosedur mysql untuk pendekatan ini dalam presentasi ini: scribd.com/doc/2569355/Geo-Distance-Search-with-MySQL
Lucia

37
Untuk mencari berdasarkan kilometer, bukan mil, ganti 3959 dengan 6371.
ErichBSchulz

4
+1, opsi bagus; menambahkan kotak mengurangi kueri saya dari 4s menjadi 0,03s rata-rata.
jvenema

1
Meskipun tampaknya sangat logis, Anda berhak mendapatkan penghargaan untuk solusi ini! Pada basis data 2 juta catatan kueri berubah dari 16 detik menjadi 0,06 detik. Catatan: Ini bahkan lebih cepat (untuk tabel besar) jika Anda memotong perhitungan jarak dari kueri dan melakukan perhitungan untuk jarak dalam kode program Anda!
NLAnaconda

2
@Binary Worrier: Jadi X1, X2 dan Y1, Y2 akan menjadi Longitude Min dan Max dan Latitude Min dan Max sesuai contoh yang diberikan di sini: blog.fedecarg.com/2009/02/08/... mohon saran.
Prabhat

14

Fungsi MySQL berikut diposting di posting blog ini . Saya belum banyak mengujinya, tetapi dari apa yang saya kumpulkan dari pos, jika bidang lintang dan bujur Anda diindeks , ini mungkin cocok untuk Anda:

DELIMITER $$

DROP FUNCTION IF EXISTS `get_distance_in_miles_between_geo_locations` $$
CREATE FUNCTION get_distance_in_miles_between_geo_locations(
  geo1_latitude decimal(10,6), geo1_longitude decimal(10,6), 
  geo2_latitude decimal(10,6), geo2_longitude decimal(10,6)) 
returns decimal(10,3) DETERMINISTIC
BEGIN
  return ((ACOS(SIN(geo1_latitude * PI() / 180) * SIN(geo2_latitude * PI() / 180) 
    + COS(geo1_latitude * PI() / 180) * COS(geo2_latitude * PI() / 180) 
    * COS((geo1_longitude - geo2_longitude) * PI() / 180)) * 180 / PI()) 
    * 60 * 1.1515);
END $$

DELIMITER ;

Penggunaan sampel:

Mengasumsikan tabel yang disebut placesdengan bidang latitude& longitude:

SELECT get_distance_in_miles_between_geo_locations(-34.017330, 22.809500,
latitude, longitude) AS distance_from_input FROM places;

Saya sudah mencoba ini dan berfungsi dengan baik, tapi entah bagaimana itu tidak memungkinkan saya untuk memasukkan pernyataan WHERE berdasarkan distance_from_input. Tahu kenapa tidak?
Chris Visser

Anda bisa melakukannya sebagai sub pilih: pilih * dari (...) karena t mana distance_from_input> 5;
Brad Parks

2
atau langsung saja dengan: pilih * dari tempat-tempat get_distance_in_miles_between_geo_locations (-34.017330, 22.809500, lintang, bujur)> 5000;
Brad Parks

2
return Meters:SELECT ROUND(((ACOS(SIN(lat1 * PI() / 180) * SIN(lat2 * PI() / 180) + COS(lat1 * PI() / 180) * COS(lat2 * PI() / 180) * COS((lnt1 - lnt2) * PI() / 180)) * 180 / PI()) * 60 * 1.1515) * 1.609344 * 1000) AS distance
Mohammad

13

Saya perlu memecahkan masalah yang sama (menyaring baris berdasarkan jarak dari satu titik) dan dengan menggabungkan pertanyaan asli dengan jawaban dan komentar, saya datang dengan solusi yang sangat cocok untuk saya di MySQL 5.6 dan 5.7.

SELECT 
    *,
    (6371 * ACOS(COS(RADIANS(56.946285)) * COS(RADIANS(Y(coordinates))) 
    * COS(RADIANS(X(coordinates)) - RADIANS(24.105078)) + SIN(RADIANS(56.946285))
    * SIN(RADIANS(Y(coordinates))))) AS distance
FROM places
WHERE MBRContains
    (
    LineString
        (
        Point (
            24.105078 + 15 / (111.320 * COS(RADIANS(56.946285))),
            56.946285 + 15 / 111.133
        ),
        Point (
            24.105078 - 15 / (111.320 * COS(RADIANS(56.946285))),
            56.946285 - 15 / 111.133
        )
    ),
    coordinates
    )
HAVING distance < 15
ORDER By distance

coordinatesadalah bidang dengan tipe POINTdan memiliki SPATIALindeks
6371untuk menghitung jarak dalam kilometer
56.946285adalah garis lintang untuk titik pusat
24.105078adalah garis bujur untuk titik pusat
15adalah jarak maksimum dalam kilometer

Dalam pengujian saya, MySQL menggunakan indeks SPATIAL di coordinateslapangan untuk dengan cepat memilih semua baris yang ada dalam persegi panjang dan kemudian menghitung jarak aktual untuk semua tempat yang disaring untuk mengecualikan tempat dari sudut persegi panjang dan hanya menyisakan tempat di dalam lingkaran.

Ini adalah visualisasi hasil saya:

peta

Bintang abu-abu memvisualisasikan semua titik di peta, bintang kuning adalah yang dikembalikan oleh permintaan MySQL. Bintang abu-abu di dalam sudut persegi panjang (tetapi lingkaran luar) dipilih oleh MBRContains()dan kemudian tidak dipilih oleh HAVINGklausa.


Tidak dapat cukup membatalkan ini. Mencari melalui tabel dengan sekitar 5 juta catatan dan indeks spasial dengan metode ini waktu pencarian adalah 0,005 detik pada prosesor A8 lama. Saya tahu bahwa 6371 dapat diganti dengan 3959 untuk mendapatkan hasil dalam mil tetapi apakah nilai 111.133 dan 111.320 perlu disesuaikan atau mereka secara universal konstan?
Wranorn

Solusi bagus
SeaBiscuit

Cara membuat Point apakah itu POINT (lat, lng) atau POINT (lng, lat)
user606669

2
@ user606669 Ini POINT (lng, lat)
Māris Kiseļovs

Fungsi X () dan Y () harus ST_Y dan ST_X saat ini.
Andreas

11

jika Anda menggunakan MySQL 5.7. *, maka Anda dapat menggunakan st_distance_sphere (POINT, POINT) .

Select st_distance_sphere(POINT(-2.997065, 53.404146 ), POINT(58.615349, 23.56676 ))/1000  as distcance

1
ini adalah alternatif yang sangat bagus dan mudah dibaca. perlu diingat, urutan parameter ke POINT () adalah (lng, lat) jika tidak, Anda akan berakhir dengan "close" tetapi hasilnya masih sangat berbeda dengan metode lain di sini. lihat: stackoverflow.com/questions/35939853/…
Andy P

9
SELECT * FROM (SELECT *,(((acos(sin((43.6980168*pi()/180)) * 
sin((latitude*pi()/180))+cos((43.6980168*pi()/180)) * 
cos((latitude*pi()/180)) * cos(((7.266903899999988- longitude)* 
pi()/180))))*180/pi())*60*1.1515 ) as distance 
FROM wp_users WHERE 1 GROUP BY ID limit 0,10) as X 
ORDER BY ID DESC

Ini adalah kueri perhitungan jarak antara ke titik di MySQL, saya telah menggunakannya dalam database yang panjang, itu berfungsi dengan sempurna! Catatan: lakukan perubahan (nama database, nama tabel, kolom dll) sesuai kebutuhan Anda.


Apa nilai mewakili 1,1515? Saya telah melihat formula yang sama sebelumnya, tetapi menggunakan 1,75 bukannya 1,1515.
TryHarder

1
Sebagai balasan untuk pertanyaan saya sendiri, saya pikir jawabannya mungkin ada di sini stackoverflow.com/a/389251/691053
TryHarder

8
set @latitude=53.754842;
set @longitude=-2.708077;
set @radius=20;

set @lng_min = @longitude - @radius/abs(cos(radians(@latitude))*69);
set @lng_max = @longitude + @radius/abs(cos(radians(@latitude))*69);
set @lat_min = @latitude - (@radius/69);
set @lat_max = @latitude + (@radius/69);

SELECT * FROM postcode
WHERE (longitude BETWEEN @lng_min AND @lng_max)
AND (latitude BETWEEN @lat_min and @lat_max);

sumber


11
Silakan kutip sumber Anda. Ini dari: blog.fedecarg.com/2009/02/08/...
redburn

Berapakah 69 dalam hal ini? Bagaimana jika seandainya kita memiliki jari-jari bumi?
CodeRunner

2
Kilometer dalam 1 Latittude adalah 111 KM. Mile in 1 Latittude berjarak 69 mil. dan 69 Mil = 111 KM. Itu sebabnya kami menggunakan parameter dalam konversi.
CodeRunner

Saya telah mencari ini selamanya. Tidak tahu itu bisa sesederhana itu. Terima kasih banyak.
Vikas

Bukankah ini salah karena lng_min / lng_max perlu menggunakan lat_min dan lat_max dalam radius matematika?
Ben

6
   select
   (((acos(sin(('$latitude'*pi()/180)) * sin((`lat`*pi()/180))+cos(('$latitude'*pi()/180)) 
    * cos((`lat`*pi()/180)) * cos((('$longitude'- `lng`)*pi()/180))))*180/pi())*60*1.1515) 
    AS distance
    from table having distance<22;

5

Fungsi MySQL yang mengembalikan jumlah meter antara dua koordinat:

CREATE FUNCTION DISTANCE_BETWEEN (lat1 DOUBLE, lon1 DOUBLE, lat2 DOUBLE, lon2 DOUBLE)
RETURNS DOUBLE DETERMINISTIC
RETURN ACOS( SIN(lat1*PI()/180)*SIN(lat2*PI()/180) + COS(lat1*PI()/180)*COS(lat2*PI()/180)*COS(lon2*PI()/180-lon1*PI()/180) ) * 6371000

Untuk mengembalikan nilai dalam format yang berbeda, ganti 6371000fungsi tersebut dengan jari-jari Earth pada unit pilihan Anda. Misalnya, kilometer akan menjadi 6371dan mil akan 3959.

Untuk menggunakan fungsi ini, panggil saja seperti yang Anda lakukan pada fungsi lain di MySQL. Misalnya, jika Anda memiliki meja city, Anda dapat menemukan jarak antara setiap kota ke setiap kota lain:

SELECT
    `city1`.`name`,
    `city2`.`name`,
    ROUND(DISTANCE_BETWEEN(`city1`.`latitude`, `city1`.`longitude`, `city2`.`latitude`, `city2`.`longitude`)) AS `distance`
FROM
    `city` AS `city1`
JOIN
    `city` AS `city2`

4

Kode lengkap dengan detail tentang cara memasang sebagai plugin MySQL ada di sini: https://github.com/lucasepe/lib_mysqludf_haversine

Saya memposting ini tahun lalu sebagai komentar. Karena @TylerCollier yang ramah menyarankan saya untuk mengirim sebagai jawaban, ini dia.

Cara lain adalah dengan menulis fungsi UDF khusus yang mengembalikan jarak haversine dari dua titik. Fungsi ini dapat menerima input:

lat1 (real), lng1 (real), lat2 (real), lng2 (real), type (string - optinal - 'km', 'ft', 'mi')

Jadi kita bisa menulis sesuatu seperti ini:

SELECT id, name FROM MY_PLACES WHERE haversine_distance(lat1, lng1, lat2, lng2) < 40;

untuk mengambil semua rekaman dengan jarak kurang dari 40 kilometer. Atau:

SELECT id, name FROM MY_PLACES WHERE haversine_distance(lat1, lng1, lat2, lng2, 'ft') < 25;

untuk mengambil semua rekaman dengan jarak kurang dari 25 kaki.

Fungsi inti adalah:

double
haversine_distance( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error ) {
    double result = *(double*) initid->ptr;
    /*Earth Radius in Kilometers.*/ 
    double R = 6372.797560856;
    double DEG_TO_RAD = M_PI/180.0;
    double RAD_TO_DEG = 180.0/M_PI;
    double lat1 = *(double*) args->args[0];
    double lon1 = *(double*) args->args[1];
    double lat2 = *(double*) args->args[2];
    double lon2 = *(double*) args->args[3];
    double dlon = (lon2 - lon1) * DEG_TO_RAD;
    double dlat = (lat2 - lat1) * DEG_TO_RAD;
    double a = pow(sin(dlat * 0.5),2) + 
        cos(lat1*DEG_TO_RAD) * cos(lat2*DEG_TO_RAD) * pow(sin(dlon * 0.5),2);
    double c = 2.0 * atan2(sqrt(a), sqrt(1-a));
    result = ( R * c );
    /*
     * If we have a 5th distance type argument...
     */
    if (args->arg_count == 5) {
        str_to_lowercase(args->args[4]);
        if (strcmp(args->args[4], "ft") == 0) result *= 3280.8399;
        if (strcmp(args->args[4], "mi") == 0) result *= 0.621371192;
    }

    return result;
}

3

Perkiraan cepat, sederhana dan akurat (untuk jarak yang lebih kecil) dapat dilakukan dengan proyeksi bola . Setidaknya dalam algoritme perutean, saya mendapat peningkatan 20% dibandingkan dengan perhitungan yang benar. Dalam kode Java sepertinya:

public double approxDistKm(double fromLat, double fromLon, double toLat, double toLon) {
    double dLat = Math.toRadians(toLat - fromLat);
    double dLon = Math.toRadians(toLon - fromLon);
    double tmp = Math.cos(Math.toRadians((fromLat + toLat) / 2)) * dLon;
    double d = dLat * dLat + tmp * tmp;
    return R * Math.sqrt(d);
}

Tidak yakin tentang MySQL (maaf!).

Pastikan Anda tahu tentang batasan (param ketiga dari assertEquals berarti akurasi dalam kilometer):

    float lat = 24.235f;
    float lon = 47.234f;
    CalcDistance dist = new CalcDistance();
    double res = 15.051;
    assertEquals(res, dist.calcDistKm(lat, lon, lat - 0.1, lon + 0.1), 1e-3);
    assertEquals(res, dist.approxDistKm(lat, lon, lat - 0.1, lon + 0.1), 1e-3);

    res = 150.748;
    assertEquals(res, dist.calcDistKm(lat, lon, lat - 1, lon + 1), 1e-3);
    assertEquals(res, dist.approxDistKm(lat, lon, lat - 1, lon + 1), 1e-2);

    res = 1527.919;
    assertEquals(res, dist.calcDistKm(lat, lon, lat - 10, lon + 10), 1e-3);
    assertEquals(res, dist.approxDistKm(lat, lon, lat - 10, lon + 10), 10);


3

Bacalah Geo Distance Search dengan MySQL , solusi berbasis implementasi Haversine Formula ke MySQL. Ini adalah deskripsi solusi lengkap dengan teori, implementasi, dan optimalisasi kinerja lebih lanjut. Meskipun bagian optimasi spasial tidak berfungsi dengan benar dalam kasus saya.

Saya perhatikan dua kesalahan dalam hal ini:

  1. penggunaan absdalam pernyataan pilih pada hal. Saya hanya dihilangkan absdan itu berhasil.

  2. fungsi jarak pencarian spasial pada p27 tidak mengkonversi ke radian atau menggandakan bujur dengan cos(latitude), kecuali data spasialnya dimuat dengan ini dalam pertimbangan (tidak dapat mengatakan dari konteks artikel), tetapi contohnya pada hal. 26 menunjukkan bahwa data spasialnya POINTtidak dimuat dengan radian atau derajat.


0
$objectQuery = "SELECT table_master.*, ((acos(sin((" . $latitude . "*pi()/180)) * sin((`latitude`*pi()/180))+cos((" . $latitude . "*pi()/180)) * cos((`latitude`*pi()/180)) * cos(((" . $longitude . "- `longtude`)* pi()/180))))*180/pi())*60*1.1515  as distance FROM `table_post_broadcasts` JOIN table_master ON table_post_broadcasts.master_id = table_master.id WHERE table_master.type_of_post ='type' HAVING distance <='" . $Radius . "' ORDER BY distance asc";

0

Menggunakan mysql

SET @orig_lon = 1.027125;
SET @dest_lon = 1.027125;

SET @orig_lat = 2.398441;
SET @dest_lat = 2.398441;

SET @kmormiles = 6371;-- for distance in miles set to : 3956

SELECT @kmormiles * ACOS(LEAST(COS(RADIANS(@orig_lat)) * 
 COS(RADIANS(@dest_lat)) * COS(RADIANS(@orig_lon - @dest_lon)) + 
 SIN(RADIANS(@orig_lat)) * SIN(RADIANS(@dest_lat)),1.0)) as distance;

Lihat: https://andrew.hedges.name/experiments/haversine/

Lihat: https://stackoverflow.com/a/24372831/5155484

Lihat: http://www.plumislandmedia.net/mysql/haversine-mysql-nearest-loc/

CATATAN: LEASTdigunakan untuk menghindari nilai nol sebagai komentar yang disarankan di https://stackoverflow.com/a/24372831/5155484

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.