Mysql
 sql >> Base de données >  >> RDS >> Mysql

Trouver tous les codes postaux à une distance spécifiée d'un code postal

Voici quelque chose que j'ai écrit il y a pas mal de temps et qui pourrait vous orienter dans la bonne direction.

Alors que vous avez demandé VB.Net, ce dont vous avez vraiment besoin est une requête qui fait un "Grand Cercle Distance " calcul pour déterminer la distance entre deux points identifiés par la latitude et la longitude.

Donc, en faisant les hypothèses suivantes :

  1. Vos données de code postal se trouvent dans un seul tableau.
  2. Cette table a des attributs pour lat et lon qui sont le centroïde approximatif du code postal

Vous pouvez utiliser une requête LINQ to SQL qui produit le jeu de résultats souhaité en utilisant quelque chose comme ceci

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

Ça a l'air compliqué, parce que ça l'est. Il y a des gens beaucoup plus intelligents ici sur SO qui peuvent expliquer l'algorithme. J'ai simplement implémenté cela à partir d'un code SQL que j'ai trouvé sur Internet - je ne me souviens plus d'où. Une recherche Google devrait vous y amener.

La première requête (zipQry) renvoie la latitude et la longitude du code postal de départ en degrés et en radians. Ces résultats sont ensuite utilisés pour exécuter la seconde requête.

La première partie de la clause WHERE dans la seconde requête :

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

Je viens de réduire la liste des codes postaux à examiner, ce qui rend la requête beaucoup plus rapide. Il ajoute un montant arbitraire à la latitude et à la longitude afin que vous ne vérifiiez pas tous les codes postaux de l'Ohio lors de la recherche d'un rayon en Californie. Le reste fait partie de l'algorithme Great Circle Distance susmentionné.

Cela aurait probablement pu être fait en une seule requête pour plus d'efficacité, mais j'en avais besoin de cette façon à l'époque, les raisons m'étaient maintenant perdues.