İki Enlem / Uzun Nokta Arasındaki Mesafeyi Bulmanın En Hızlı Yolu


227

Şu anda tüm boylam ve enlem bilgileri ile bir mysql veritabanında bir milyonun altında yerleri var.

Bir sorgu ile bir nokta ve diğer birçok nokta arasındaki mesafeyi bulmaya çalışıyorum. Özellikle saniyede 100'den fazla vuruşla olmasını istediğim kadar hızlı değil.

Bunun için daha hızlı bir sorgu veya mysql dışında daha hızlı bir sistem var mı? Bu sorguyu kullanıyorum:

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;

Not: Sağlanan mesafe Mil cinsindendir . Kilometreye ihtiyacınız varsa 6371yerine kullanın 3959.


31
Verdiğiniz formülün sabit olan birçok unsuru var gibi görünüyor. Verileri önceden hesaplamak ve bu değerleri DB'nizde depolamak mümkün mü? Örneğin 3959 * acos (cos (radyan (42,290763)) bir sabittir ama içinde 4 büyük hesaplamaları vardır Onun yerine sadece 6696.7837 depolayabilir.?
Peter M

1
Veya en azından sorgu dışında sabitleri önceden hesapla? Bu yapılması gereken işi azaltacaktır.
Peter M

2
@Peter M İyi bir SQL veritabanının sadece bir kez hesaplanacağı şekilde optimize edilmesi muhtemel görünüyor.
mhenry1384

25
Merak edenler için 42.290763 enlem ve -71.35368 mesafeleri hesaplamak için kullanılan noktanın boylamıdır.
user276648

14
Sadece bilgi için, Mesafe bu formül mil olduğunu tarafından değil, kilometers.Please içinde kilometre olarak sonuç almak için 6371 için 3959 değiştirin caluclated
Sahil

Yanıtlar:


115
  • Tablodaki veri türlerinin Pointdeğerlerini kullanarak puanlarınızı oluşturun . Mysql 5.7.5 itibariyle, tablolar artık endeksleri de desteklemektedir .GeometryMyISAMInnoDBSPATIAL

  • SPATIALBu noktalarda bir dizin oluşturun

  • MBRContains()Değerleri bulmak için kullanın :

    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)
    

, veya içinde MySQL 5.1ve üstünde:

    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
                    )

Bu yaklaşık olarak kutudaki tüm noktaları seçecektir (@lat +/- 10 km, @lon +/- 10km).

Bu aslında bir kutu değil, küresel bir dikdörtgen: kürenin enlem ve boylam bağlı bölümü. Bu, Franz Joseph Land'deki düz bir dikdörtgenden farklı olabilir , ancak çoğu yerleşim yerinde buna oldukça yakındır.

  • Dairenin içindeki her şeyi seçmek için ek filtreleme uygulayın (kare değil)

  • Büyük daire mesafesini (büyük mesafeler için) hesaba katmak için muhtemelen ek ince filtreleme uygulayın


15
@Quassnoi: Birkaç düzeltme: Muhtemelen koordinatların sırasını lat, uzun olarak değiştirmek isteyeceksiniz. Ayrıca, uzunlamasına mesafeler enlemin kosinüsü ile orantılıdır, boylam değil. Ve Eğer ilk olarak düzeltilmiş olacaktır koordinat böylece lige çarpma şeklinde değiştirmeyi isteyeceksiniz @lon - 10 / ( 111.1 / cos(@lat))her şeyin doğru olduğunu bir kez çifti ikinci (ve olmayacak.
M. Dave Auayan

8
UYARI : Cevabın gövdesi @M tarafından yapılan çok geçerli yoruma göre DEĞİLDİR. Dave Auayan. İlave notlar: İlgilenilen daire (a) bir kutup içeriyorsa veya (b) +/- 180 derece boylam meridyeni ile kesişiyorsa bu yöntem önceden şekillendirilir. Ayrıca cos(lon)sadece ufacık mesafelerde kullanmak doğrudur. Bkz. Janmatuschek.de/LatitudeLongitudeBurgulamaKoordinatları
John Machin

3
Sabitlerin (10, 111.11, @lat, @lon, mypoint) neyi temsil ettiği hakkında bir fikir edinebilmemizin bir yolu var mı? 10'un kilometrelerce mesafe olduğunu varsayıyorum, @lat ve @lon sağlanan kafes ve boylamı temsil ediyor, ancak örnekte 111.11 ve mypoint neyi temsil ediyor?
17'de ashays

4
@ashays: 111.(1)enlem derecesinde yaklaşık olarak km vardır . mypointtablodaki koordinatları saklayan alandır.
Quassnoi

1
Başka bir hata düzeltmesi - bir kapanış eksik - ikinci satırdan son satıra
ina

100

MySql'e özel bir cevap değil, ancak sql ifadenizin performansını artıracaktır.

Etkili bir şekilde yaptığınız, belirli bir noktanın 10 birimi içinde olup olmadığını görmek için tablodaki her noktaya olan mesafeyi hesaplamaktır.

Bu sql çalıştırmadan önce yapabileceğiniz şey, noktanızı merkezde yani bir tarafa 20 birim çizen dört nokta oluşturmaktır. (x1, y1). . . (x4, y4) (burada x1, y1) 'dir (verilen + 10 birim boyunca, verilen + 10 birim). . . (verilenUzun - 10 birim, verilen -L-10 birim). Aslında, sadece iki noktaya ihtiyacınız var, sol üst ve sağ alt onları (X1, Y1) ve (X2, Y2) olarak adlandırın

Şimdi SQL ifadeniz, verilen noktaları kesinlikle 10u'dan fazla olan satırları hariç tutmak için bu noktaları kullanır, enlemlerde ve boylamlarda dizinleri kullanabilir, bu nedenle şu anda sahip olduğunuzdan daha hızlı büyüklük siparişleri olacaktır.

Örneğin

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

Kutu yaklaşımı yanlış pozitifler döndürebilir (kutunun köşelerinde verilen noktadan> 10u olan noktaları toplayabilirsiniz), bu yüzden yine de her noktanın mesafesini hesaplamanız gerekir. Ancak bu çok daha hızlı olacaktır çünkü test edilecek nokta sayısını kutu içindeki noktalarla büyük ölçüde sınırlandırdınız.

Bu tekniğe "kutunun içinde düşünmek" diyorum :)

EDIT: Bu bir SQL deyimi içine konabilir mi?

MySql veya Php'nin neler yapabileceği hakkında hiçbir fikrim yok, üzgünüm. Nerede dört nokta oluşturmak için en iyi yer olduğunu bilmiyorum, ya da nasıl Php bir mySql sorgusu geçirilebilir. Ancak, dört noktaya sahip olduğunuzda, kendi SQL ifadenizi benimkilerle birleştirmenizi engelleyen hiçbir şey yoktur.

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;

MS SQL ile biliyorum Ben dört kayan (X1, Y1, X2, Y2) bildirir ve "ana" select deyiminden önce hesaplar bir SQL deyimi oluşturabilir, dediğim gibi, bu ile yapılabilir eğer hiçbir fikrim yok MySQL. Ancak yine de C # dört puan oluşturmak ve SQL sorgusu için parametre olarak bunları geçirmek eğiliminde olacaktır.

Maalesef daha fazla yardım edemem, eğer herkes bunun MySQL ve Php'ye özgü kısımlarına cevap verebilirse, bu cevabı düzenlemek için çekinmeyin.


4
Bu sunum için bir mysql yordamı bu sunumda bulabilirsiniz: scribd.com/doc/2569355/Geo-Distance-Search-with-MySQL
Lucia

37
Mil yerine kilometre araması yapmak için 3959 yerine 6371 yazın.
ErichBSchulz

4
+1, mükemmel seçenek; kutuyu eklemek sorgumu 4s'den 0.03s'ye düşürdü avg.
jvenema

1
Bu kadar mantıklı görünse de, bu çözüm için bir ödül ayırıyorsunuz! 2 Milyonluk bir kayıt veritabanında sorgu 16 saniyeden 0.06 saniyeye çıktı. Not: Mesafe hesaplamasını sorgudan kesip program kodunuzdaki mesafe için hesaplamayı yaparsanız daha da hızlıdır (büyük tablolar için)!
NLAnaconda

2
@Binary Worrier: Yani X1, X2 ve Y1, Y2, burada verilen örneğe göre Boylam Min ve Maks ve Enlem Min ve Maks olacaktır: blog.fedecarg.com/2009/02/08/… lütfen tavsiye edin.
Prabhat

14

Bu blog gönderisine aşağıdaki MySQL işlevi gönderildi . Çok fazla test etmedim, ancak postadan topladığımdan, enlem ve boylam alanlarınız dizine eklenmişse , bu sizin için iyi olabilir:

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 ;

Örnek kullanım:

Denilen bir tablo varsayarsak placesalanları ile latitude& longitude:

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

Bunu denedim ve mükemmel çalışıyor, ama bir şekilde bana distance_from_input dayalı bir WHERE deyimi koymak için izin vermez. Neden olmasın?
Chris Visser

bunu bir alt seçim olarak yapabilirsiniz: t olarak distance_from_input> 5;
Brad Parks

2
veya doğrudan şununla git: get_distance_in_miles_between_geo_locations (-34.017330, 22.809500, enlem, boylam)> 5000;
Brad Parks

2
Dönüş Metre: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
Muhammed

13

Benzer bir sorunu çözmem gerekiyordu (satırları tek noktadan mesafeye göre filtrelemek) ve orijinal soruyu cevaplarla ve yorumlarla birleştirerek, hem MySQL 5.6 hem de 5.7'de mükemmel çalışan bir çözüm buldum.

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

coordinatestipi ile alan POINTve SPATIALendeksi
6371kilometre
56.946285cinsinden mesafeyi hesaplamak içindir merkezi nokta
24.105078için enlemdir merkezi nokta için boylam
15kilometre olarak maksimum mesafe

Testlerimde, MySQL, coordinatesdikdörtgen içindeki tüm satırları hızlı bir şekilde seçmek için SPATIAL dizinini kullanır ve daha sonra, yerleri dikdörtgen köşelerinden hariç tutmak ve yalnızca dairenin içindeki yerleri bırakmak için filtrelenen tüm yerler için gerçek mesafeyi hesaplar.

Bu benim sonucumun görselleştirilmesidir:

harita

Gri yıldızlar haritadaki tüm noktaları görselleştirir, sarı yıldızlar MySQL sorgusu tarafından döndürülen yıldızlardır. Dikdörtgenin köşelerindeki (ancak dairenin dışındaki) gri yıldızlar MBRContains(), HAVINGcümle ile seçildi ve daha sonra madde seçimi kaldırıldı .


Bunu yeterince değerlendiremiyorum. Bu yöntemle yaklaşık 5 milyon kayıt ve bir uzamsal indeks içeren bir tablodan arama yapmak için arama süresi eski bir A8 işlemcide 0.005 saniyedir. Milleri mil olarak almak için 6371'in 3959 ile değiştirilebileceğini biliyorum, ancak 111.133 ve 111.320 değerlerinin ayarlanması gerekiyor mu yoksa evrensel olarak sabit mi?
Wranorn

Harika bir çözüm.
SeaBiscuit

Point nasıl oluşturulur POINT (lat, lng) veya POINT (lng, lat)
user606669

2
@ user606669 It's POINT (lng, lat)
Māris Kiseļovs

X () ve Y () işlevi günümüzde ST_Y ve ST_X olmalıdır.
Andreas

11

MySQL 5.7. * kullanıyorsanız, st_distance_sphere (POINT, POINT) kullanabilirsiniz .

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

1
bu çok iyi ve okunması kolay bir alternatiftir. unutmayın, POINT () parametresinin sırası (lng, lat) 'dir, aksi takdirde "close" ile sonuçlanabilir, ancak yine de buradaki diğer yöntemlerden çok farklı sonuçlar elde edersiniz. bkz. 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

Bu MySQL noktaları arasında mesafe hesaplama sorgusu, uzun bir veritabanında kullandım, mükemmel çalışıyor! Not: Gereksinimlerinize göre değişiklikleri (veritabanı adı, tablo adı, sütun vb.) Yapın.


1.1515 değeri neyi temsil ediyor? Daha önce benzer bir formül gördüm, ancak 1.1515 yerine 1.75 kullandı.
TryHarder

1
Kendi soruma cevap olarak, cevabın burada yattığını düşünüyorum 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);

kaynak


11
Lütfen kaynaklarınızı belirtin. Bu kaynak: blog.fedecarg.com/2009/02/08/…
redburn

Bu durumda 69 nedir? Dünya yarıçapına sahipsek nasıl yapılır?
CodeRunner

2
1 Enlemde Kilometre 111 KM'dir. 1 Latittude'da mil 112 km uzaklıktadır. ve 69 Mil = 111 KM. Bu yüzden dönüşümlerdeki parametreleri kullandık.
CodeRunner

Bunu sonsuza kadar arıyordum. Bu kadar basit olabileceğini bilmiyordum. Çok teşekkür ederim.
Vikas

Yarıçap matematikte lng_min / lng_max 'ın lat_min ve lat_max' ı kullanması gerekeceğinden bu yanlış olmaz mıydı?
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

İki koordinat arasındaki sayaç sayısını döndüren bir MySQL işlevi:

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

Değeri farklı bir biçimde döndürmek için 6371000, işlevdeki birim birim seçiminde Dünya yarıçapı ile değiştirin . Örneğin kilometreler 6371ve kilometreler olurdu 3959.

İşlevi kullanmak için, MySQL'deki diğer işlevlerde olduğu gibi çağırmanız yeterlidir. Örneğin, bir masanız varsa city, her şehir ile diğer şehirler arasındaki mesafeyi bulabilirsiniz:

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

MySQL eklentisi olarak nasıl yükleneceği ile ilgili ayrıntıların tam kodu: https://github.com/lucasepe/lib_mysqludf_haversine

Bunu geçen yıl yorum olarak gönderdim. Nazikçe @TylerCollier cevap olarak göndermemi önerdiğinden, işte burada.

Başka bir yol, iki noktadan haversin mesafesini döndüren özel bir UDF işlevi yazmaktır. Bu işlev girişi alabilir:

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

Böylece şöyle bir şey yazabiliriz:

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

40 kilometreden daha kısa bir mesafeye sahip tüm kayıtları almak için. Veya:

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

25 fit'ten daha kısa bir mesafeye sahip tüm kayıtları almak için.

Çekirdek işlevi:

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

Küresel projeksiyon ile hızlı, basit ve doğru (daha küçük mesafeler için) bir yaklaşım yapılabilir . En azından yönlendirme algoritmamda doğru hesaplamaya kıyasla% 20 artış elde ediyorum. Java kodunda şöyle görünür:

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);
}

MySQL hakkında emin değilim (üzgünüm!).

Sınırlamayı bildiğinizden emin olun (assertEquals'ın üçüncü parametresi kilometre olarak doğruluk anlamına gelir):

    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

Haversine Formula'nın MySQL'e uygulanmasına dayanan bir çözüm olan MySQL ile Coğrafi Mesafe Arama'yı okuyun . Bu teori, uygulama ve daha fazla performans optimizasyonu ile eksiksiz bir çözüm tanımıdır. Mekansal optimizasyon kısmı benim durumumda düzgün çalışmadı.

Bunda iki hata fark ettim:

  1. absp8'deki select deyiminde kullanımı . Sadece atladım absve işe yaradı.

  2. p27'deki uzamsal arama mesafesi işlevi, cos(latitude)uzamsal verileri dikkate alındığında (makalenin bağlamından anlayamaz) radyanlara dönüştürülmez veya boylamı çarpmaz, ancak p26'daki örneği, uzamsal verilerinin POINTyüklenmediğini gösterir. radyan veya derece.


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

Mysql kullanma

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;

Bkz. Https://andrew.hedges.name/experiments/haversine/

Bkz. Https://stackoverflow.com/a/24372831/5155484

Bkz. Http://www.plumislandmedia.net/mysql/haversine-mysql-nearest-loc/

NOT: https://stackoverflow.com/a/24372831/5155484 adresindeLEAST önerilen bir yorum olarak null değerlerden kaçınmak için kullanılır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.