Pregunta

Nota:. Aunque yo uso una base de datos con código postal códigos postales holandeses, esta pregunta es país independiente

Tengo una base de datos con cada código postal en los Países Bajos + su coordenadas X e Y (latitud / longitud).

Tengo, por ejemplo, código postal: $baseZipCode = 1044; con las siguientes coordenadas:

x coordinate = 4,808855
y coordinate = 52,406332

Ahora, quiero encontrar todos los demás códigos postales con $range de $baseZipCode.

Por ejemplo:

SELECT
  zipcode
FROM
  zipcodes
WHERE
  ????? // Need help here

El problema es que la tierra no es completamente redonda. Me parece una gran cantidad de tutoriales con cálculos from a to b pero eso no es lo que necesito.

¿Alguien tiene alguna idea?


Actualizar Gracias a Captaintokyo yo encontramos este:

¿Quieres encontrar todos los códigos postales y las correspondientes distancias dentro de un cierto radio de una milla / kilómetro de otro código postal o punto? Estos problemas requieren coordenadas de latitud y longitud para resolver. Geocodificación de la dirección le da las coordenadas latitud / longitud de una dirección.

En primer lugar se necesita una base de datos de todos los códigos postales y sus correspondientes coordenadas de latitud y longitud:

CREATE TABLE `zipcodes` (
  `zipcode` varchar(5) NOT NULL DEFAULT '',
  `city` varchar(100) NOT NULL DEFAULT '',
  `state` char(2) NOT NULL DEFAULT '',
  `latitude` varchar(20) NOT NULL DEFAULT '',
  `longitude` varchar(20) NOT NULL DEFAULT '',
  KEY `zipcode` (`zipcode`),
  KEY `state` (`state`)
)

Así que una vez que tenga la base de datos que desea encontrar todos los códigos postales en un radio determinado millas de un punto central. Si el punto central es otro código postal, sólo tiene que consultar la base de las coordenadas de latitud y longitud de ese código postal. A continuación, el código es el siguiente:

// ITITIAL POINT

$coords = array('latitude' => "32.8", 'longitude' => "-117.17");

//RADIUS

$radius = 30;

// SQL FOR KILOMETERS

$sql = "SELECT zipcode, ( 6371 * acos( cos( radians( {$coords['latitude']} ) ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians( {$coords['longitude']} ) ) + sin( radians( {$coords['latitude']} ) ) * sin( radians( latitude ) ) ) ) AS distance FROM zipcodes HAVING distance <= {$radius} ORDER BY distance";

// SQL FOR MILES

$sql = "SELECT zipcode, ( 3959 * acos( cos( radians( {$coords['latitude']} ) ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians( {$coords['longitude']} ) ) + sin( radians( {$coords['latitude']} ) ) * sin( radians( latitude ) ) ) ) AS distance FROM zipcodes HAVING distance <= {$radius} ORDER BY distance";

// OUTPUT THE ZIPCODES AND DISTANCES

$query = mysql_query($sql);

while($row = mysql_fetch_assoc($query)){

    echo "{$row['zipcode']} ({$row['distance']})<br>\n";

}

(Tanto Yahoo y Google ofrecen servicios de geocodificación libres.)

¿Fue útil?

Solución

¿Quieres hacer algo como esto:

SELECT zipcode FROM zipcodes WHERE DistanceFormula(lat, long, 4.808855, 52.406332) < $range

Puede ser lento si la tabla de códigos postales es grande. También es posible que desee comprobar hacia fuera las extensiones geoespaciales para MySQL.

Otros consejos

Usted tiene que usar algo llamado el Haversine fórmula :

$sql = "
    SELECT zipcode
    FROM zipcodes
    WHERE ".mysqlHaversine($lat, $lon, $distance)."
";

Y la fórmula:

function mysqlHaversine($lat = 0, $lon = 0, $distance = 0)
{
    if($distance > 0)
    {
        return ('
        ((6372.797 * (2 *
        ATAN2(
            SQRT(
                SIN(('.($lat*1).' * (PI()/180)-latitude*(PI()/180))/2) *
                SIN(('.($lat*1).' * (PI()/180)-latitude*(PI()/180))/2) +
                COS(latitude * (PI()/180)) *
                COS('.($lat*1).' * (PI()/180)) *
                SIN(('.($lon*1).' * (PI()/180)-longitude*(PI()/180))/2) *
                SIN(('.($lon*1).' * (PI()/180)-longitude*(PI()/180))/2)
                ),
            SQRT(1-(
                SIN(('.($lat*1).' * (PI()/180)-latitude*(PI()/180))/2) *
                SIN(('.($lat*1).' * (PI()/180)-latitude*(PI()/180))/2) +
                COS(latitude * (PI()/180)) *
                COS('.($lat*1).' * (PI()/180)) *
                SIN(('.($lon*1).' * (PI()/180)-longitude*(PI()/180))/2) *
                SIN(('.($lon*1).' * (PI()/180)-longitude*(PI()/180))/2)
            ))
        )
        )) <= '.($distance/1000). ')');
    }

    return '';
}

Por lo general, no lo use el código sin entender la forma en que funciona la primera, pero debo confesar esta función es un poco por encima de mi cabeza ...

Si bien el método de Captaintokyo es preciso, también es bastante lento. No puedo evitar pensar que sería más ventajoso utilizar una tabla temporal de todos los códigos postales cuyos límites están dentro del rango, entonces para refinar los resultados por distancia.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top