Mysql
 sql >> Database >  >> RDS >> Mysql

Trova tutti i codici postali entro la distanza specificata da un codice postale

Ecco qualcosa che ho scritto un po' di tempo fa che potrebbe portarti nella giusta direzione.

Anche se hai chiesto VB.Net, ciò di cui hai veramente bisogno è una query che faccia un "Great Circle Distanza " calcolo per determinare la distanza tra due punti identificati da latitudine e longitudine.

Quindi, facendo le seguenti ipotesi:

  1. I dati del tuo codice postale si trovano in un'unica tabella.
  2. Tale tabella ha attributi per lat e lon che sono il baricentro approssimativo del codice postale

È possibile utilizzare una query LINQ to SQL che produce il set di risultati desiderato utilizzando qualcosa del genere

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

Sembra complicato, perché lo è. Ci sono persone molto più intelligenti qui su SO che possono spiegare l'algoritmo. L'ho semplicemente implementato da un codice SQL che ho trovato su Internet - non riesco a ricordare da dove. Una ricerca su Google dovrebbe portarti lì.

La prima query (zipQry) restituisce la lat e la lon del codice postale iniziale in gradi e radianti. Questi risultati vengono quindi utilizzati per eseguire la seconda query.

La prima parte della clausola WHERE nella seconda query:

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) _

Ho appena ristretto l'elenco dei codici postali da esaminare, rendendo la query molto più veloce. Aggiunge un importo arbitrario al lat e al lon in modo da non controllare tutti i codici postali in Ohio durante la ricerca di un raggio in California. Il resto fa tutto parte del summenzionato algoritmo Great Circle Distance.

Probabilmente avrebbe potuto essere fatto in una query per una maggiore efficienza, ma all'epoca ne avevo bisogno in questo modo, le ragioni ora per me sono state perse.