Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Encontre todos os CEPs dentro da distância especificada de um CEP


Aqui está algo que escrevi há algum tempo que pode colocá-lo na direção correta.

Enquanto você pediu VB.Net, o que você realmente precisa é de uma consulta que faça um "Great Circle Distância " cálculo para determinar a distância entre dois pontos identificados por latitude e longitude.

Então, fazendo as seguintes suposições:
  1. Seus dados de CEP estão em uma única tabela.
  2. A referida tabela tem atributos para lat e lon que são o centroide aproximado do CEP

Você pode usar uma consulta LINQ to SQL que produz o conjunto de resultados desejado usando algo assim
Const EARTH_RADIUS As Single = 3956.0883313286095
Dim radCvtFactor As Single = Math.PI / 180
Dim zipCodeRadius As Integer = <Your Radius Value>

Dim zipQry = From zc In db.ZipCodes 
             Where zc.Zip = "<Your Zip Code>" _
             Select zc.Latitude, 
                    zc.Longitude, 
                    ZipLatRads = RadCvtFactor * zc.Latitude, 
                    ZipLonRads = RadCvtFactor * zc.Longitude
Dim zipRslt = zipQry.SingleOrDefault()
If zipRslt IsNot Nothing Then
    Dim zcQry = From zc In db.ZipCodes _
                Where zc.Latitude >= (zipRslt.Latitude - 0.5) And zc.Latitude <= (zipRslt.Latitude + 0.5) _
                And zc.Longitude >= (zipRslt.Longitude - 0.5) And (zc.Longitude <= zipRslt.Longitude + 0.5) _
                And Math.Abs(EARTH_RADIUS * (2 * Math.Atan2(Math.Sqrt(Math.Pow(Math.Sin(((RadCvtFactor * zc.Latitude) - zipRslt.ZipLatRads) / 2), 2) + _
                Math.Cos(zipRslt.ZipLatRads) * Math.Cos(RadCvtFactor * zc.Latitude) * _
                Math.Pow(Math.Sin(((RadCvtFactor * zc.Longitude) - zipRslt.ZipLonRads) / 2), 2)), _
                Math.Sqrt(1 - Math.Pow(Math.Sin(((RadCvtFactor * zc.Latitude) - zipRslt.ZipLatRads) / 2), 2) + _
                Math.Cos(zipRslt.ZipLatRads) * Math.Cos(RadCvtFactor * zc.Latitude) * _
                Math.Pow(Math.Sin((RadCvtFactor * zc.Longitude) / 2), 2))))) <= zipCodeRadius _
                Select zc
End If

Parece complicado, porque é. Existem pessoas muito mais inteligentes aqui no SO que podem explicar o algoritmo. Eu apenas implementei isso de algum código SQL que encontrei na internet - não me lembro de onde. Uma busca no Google deve te levar até lá.

A primeira consulta (zipQry) retorna o lat e o lon do CEP inicial em graus e radianos. Esses resultados são usados ​​para executar a segunda consulta.

A primeira parte da cláusula WHERE na segunda consulta:
Where zc.Latitude >= (zipRslt.Latitude - 0.5) And zc.Latitude <= (zipRslt.Latitude + 0.5) _
And zc.Longitude >= (zipRslt.Longitude - 0.5) And (zc.Longitude <= zipRslt.Longitude + 0.5) _

Apenas reduzimos a lista de CEPs a serem examinados, tornando a consulta muito mais rápida. Ele adiciona uma quantidade arbitrária ao lat e lon para que você não verifique todos os CEPs em Ohio ao pesquisar um raio na Califórnia. O resto é tudo parte do algoritmo Great Circle Distance acima mencionado.

Isso provavelmente poderia ter sido feito em uma consulta para maior eficiência, mas eu precisava dessa maneira na época, os motivos agora perdidos para mim.