MySQL kullanarak mesafedeki noktaları bulun


20

Kullanıcı adı, enlem ve boylam ile bir mySQL tablo var. Belirli bir enlem ve boylamın dairesi veya karesi içinde belirli bir mesafe ile olan bir kullanıcı listesi almak istiyorum. Örneğin Lat = 78.3232 ve Uzun = 65.3234 ve mesafe = 30 mil girdim. 78.3232 ve 65.3234 noktalarından 30 mil uzaklıktaki kullanıcıların listesini almak istiyorum. Bunu tek bir sorgu ile çözmek mümkün müdür? Yoksa bana bu sorguyu çözmeye başlamak için bir ipucu verebilir misiniz? Coğrafi bilgi konusunda yeniyim.


Neden PostGIS olmasın? Coğrafi projeye başlıyorsanız,
yığınızı

stackoverflow.com/a/40272394/1281385 Bu sorguyu hızlandırmada yararlı olmalı (gerekirse)
exussum

Yanıtlar:


32

78.3232, 65.3234 koordinatına 30 mil yarıçap içinde en yakın 20 konumu bulan SQL deyimi. Mesafeyi, o satırın enlem / boylamına ve hedef enlem / boylama göre hesaplar ve sonra yalnızca mesafe değerinin 30 milden az olduğu satırları sorar, tüm sorguyu mesafeye göre sıralar ve 20 sonuçla sınırlar. Mil yerine kilometre ile arama yapmak için 3959 yerine 6371 yazın.

SELECT
  id, (
    3959 * acos (
      cos ( radians(78.3232) )
      * cos( radians( lat ) )
      * cos( radians( lng ) - radians(65.3234) )
      + sin ( radians(78.3232) )
      * sin( radians( lat ) )
    )
  ) AS distance
FROM markers
HAVING distance < 30
ORDER BY distance
LIMIT 0 , 20;

Bu, Google Haritalar API v3'ü zaten sahip olduğunuz bir MySQL arka ucuyla kullanıyor.

https://developers.google.com/maps/articles/phpsqlsearch_v3#findnearsql


Bunu kullanarak benim sözdizimi hatası alıyorum, "# 1582 - Yerel işlev 'radyanlar' çağrısında yanlış parametre sayısı ne olabilir?
bluantinoo

Bulunan: lng değişkenini boş bıraktım! afedersiniz!
bluantinoo

Tam olarak ne istedim, ama binlerce kayıt için sorgu performansı aşırı yük nedir? ve doğruluk nasıl?
Amit Shah

1
metre ile aramak için 6371392.896 ile değiştirmek çok daha iyi
Vasilii Suricov

34

Mapperz'nin cevabı geçersiz. Sinüs enlemden hesaplanmalı ve boylamdan hesaplanmamalıdır. Yani corect SQL deyimi:

SELECT
    id, (
      3959 * acos (
      cos ( radians(78.3232) )
      * cos( radians( lat ) )
      * cos( radians( lng ) - radians(65.3234) )
      + sin ( radians(78.3232) )
      * sin( radians( lat ) )
    )
) AS distance
FROM markers
HAVING distance < 30
ORDER BY distance
LIMIT 0 , 20;

Cevabınız 1.
Amit Shah

@AmitShah Askere ping atabileceğinizi düşünüyorsanız (shihabK yaklaşık 6 yıldır aktif değil) ve / veya meta.stackexchange.com/questions/268666/…
PolyGeo

Bu kabul edilen cevap olmalı.
catbadger

2

Bir fonksiyon yaratmak temel olabilir, böylece diğer alanları tekrar kullanabilirsiniz. Ayrıca sorgunuzu biraz daha temiz yapar ... En azından benim 2 sent.

DELIMITER $$

create function calcDistance(lat float, lng float, pnt_lat float, pnt_lng float)

Returns float
BEGIN

Declare dist float;
SET dist =
  3959 * acos (
  cos ( radians(pnt_lat) )
  * cos( radians( lat ) )
  * cos( radians( lng ) - radians(pnt_lng) )
  + sin ( radians(pnt_lat) )
  * sin( radians( lat ) )
);

RETURN dist;

END

kod stilini düzeltirseniz cevap kaldırılacaktır. doğru yol
Vasilii Suricov

0

İşte benim sorgu çeşidim, biraz daha kolay görünüyor ( http://dexxtr.com/post/83498801191/how-to-determine-point-inside-circle-using-mysql )

SELECT 
    *
FROM 
    `locator`
WHERE
    SQRT(POW(X(`center`) - 49.843317 , 2) + POW(Y(`center`) - 24.026642, 2)) * 100 < `radius`

4
Daha kolay ama dünyanın kavisli olduğu gerçeğini görmezden geliyor.
Tim Rijavec

Doğru olmak için bir formüle ihtiyacınız var. Belki bu sadece kısa mesafelerde iyi olurdu: D
Jethro

Bir füze falan fırlatacak mısın?
Dennis Braga

1
@DennisBraga - öyleyse, belki de bu soru konu dışı, http://globalthermonuclearwar.stackexchange.com için daha uygun ...?
ashleedawg
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.