Encontre pontos à distância usando o MySQL


20

Eu tenho uma tabela mySQL com nome de usuário, latitude e longitude do usuário. Gostaria de obter uma lista de usuários que estão dentro do círculo ou quadrado de uma determinada latitude e longitude com determinada distância. Por exemplo, minha entrada Lat = 78.3232 e Long = 65.3234 e distância = 30 milhas. Gostaria de obter a lista de usuários que estão a 48 km do ponto 78.3232 e 65.3234. É possível resolver isso com uma única consulta? Ou você pode me dar uma dica para começar a resolver esta consulta? Eu sou novo nas informações geográficas.


Por que não o PostGIS? Se você está começando projeto geo você ainda pode mudar sua pilha
simplexio

stackoverflow.com/a/40272394/1281385 Deve ser útil para acelerar esta consulta (se necessário)
exussum

Respostas:


32

A instrução SQL que encontrará os 20 locais mais próximos que estão dentro de um raio de 30 milhas para a coordenada 78,3232, 65,3234. Ele calcula a distância com base na latitude / longitude dessa linha e na latitude / longitude alvo e solicita apenas linhas onde o valor da distância é inferior a 48 quilômetros, ordena toda a consulta por distância e a limita a 20 resultados. Para pesquisar por quilômetros em vez de milhas, substitua 3959 por 6371.

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;

Isso está usando a API do Google Maps v3 com um back-end do MySQL que você já possui.

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


Estou recebendo um erro de sintaxe no meu select usando este ", # 1582 - Contagem incorreta de parâmetros na chamada para a função nativa 'radianos', o que poderia ser?
bluantinoo

Encontrado: eu tinha a variável lng vazia! Desculpe!
bluantinoo

Exatamente o que eu queria, mas qual é a sobrecarga de desempenho da consulta para milhares de registros? e quanto à precisão?
Amit Shah

1
muito melhor substituí-lo para 6371392.896 para pesquisar por metros
Vasilii Suricov

34

A resposta do Mapperz é inválida. O seio deve ser calculado a partir da latitude e NÃO da longitude. Portanto, a instrução SQL correta é:

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;

Sua resposta deve ser solicitada em primeiro lugar.
Amit Shah

@AmitShah Se você acha que pode executar ping no solicitante (@shihabK que não está ativo no site há quase 6 anos) e / ou votar em meta.stackexchange.com/questions/268666/…
PolyGeo

Essa deve ser a resposta aceita.
catbadger 28/09

2

Pode ser a base para criar uma função .. para que você possa reutilizá-la em outras áreas. Também tornaria sua consulta um pouco mais limpa ... Pelo menos esses são meus 2 centavos.

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

a resposta será votada se você corrigir o estilo de código. é o caminho certo
Vasilii Suricov 06/02

0

Aqui está minha variante de consulta, parece um pouco mais fácil ( 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
É mais fácil, mas ignora o fato de que a terra é curva.
precisa saber é o seguinte

Precisa de uma fórmula para ser preciso. Talvez isso seja bom apenas em distâncias curtas: D
Jethro

Você vai lançar um míssil, ou algo assim?
Dennis Braga

1
@DennisBraga - se sim, então talvez essa pergunta seja fora de tópico, mais adequada para http://globalthermonuclearwar.stackexchange.com ...?
ashleedawg
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.