En este post te voy a mostrar una fórmula de MySQL para calcular la distancia entre dos coordenadas GPS (latitud y longitud) en metros, de modo que podrás calcular la cantidad de metros que existen entre 2 puntos geográficos al hacer consultas SQL.
Debido a que vamos a definir la fórmula como una función de MySQL vas a poder usarla al hacer cualquier operación como SELECT o INSERT.
Vamos a usar la fórmula de Haversine también llamada semiverseno, misma que permite conocer la distancia de círculo máximo entre dos puntos de un globo sabiendo su longitud y su latitud.
Definición de Haversine con MySQL
La siguiente función para calcular la distancia entre 2 coordenadas con MySQL te va a devolver la distancia en metros; obviamente puedes convertirla a kilómetros o metros.
El código SQL es el siguiente:
DELIMITER //
CREATE FUNCTION haversine(lat1 DOUBLE, lon1 DOUBLE, lat2 DOUBLE, lon2 DOUBLE)
RETURNS DOUBLE
DETERMINISTIC
BEGIN
DECLARE RADIO_TIERRA_EN_KILOMETROS DOUBLE DEFAULT 6371.0;
DECLARE deltaLongitud DOUBLE;
DECLARE deltaLatitud DOUBLE;
DECLARE halfChordLengthSquared DOUBLE;
DECLARE angularDistanceRadians DOUBLE;
DECLARE distanciaMetros DOUBLE;
-- Convertir las coordenadas de grados a radianes
SET lat1 = RADIANS(lat1);
SET lon1 = RADIANS(lon1);
SET lat2 = RADIANS(lat2);
SET lon2 = RADIANS(lon2);
-- Calcular las diferencias
SET deltaLongitud = lon2 - lon1;
SET deltaLatitud = lat2 - lat1;
-- Aplicar la fórmula del haversine
SET halfChordLengthSquared = POW(SIN(deltaLatitud / 2), 2) + COS(lat1) * COS(lat2) * POW(SIN(deltaLongitud / 2), 2);
SET angularDistanceRadians = 2 * ATAN2(SQRT(halfChordLengthSquared), SQRT(1 - halfChordLengthSquared));
SET distanciaMetros = RADIO_TIERRA_EN_KILOMETROS * angularDistanceRadians * 1000; -- Convertir a metros
RETURN distanciaMetros;
END //
DELIMITER ;
Solo debes ejecutarlo en tu base de datos una vez, y después vas a poder calcular la distancia entre coordenadas con MySQL en cualquier tabla. Incluso puedes probarla sin tabla, por ejemplo:
SELECT haversine(19.416326917410476, -99.12479042256915, 23.097069089850933, -82.35006433419622);
La salida de esa consulta será 1784668.3798590573 lo cual es correcto según mi otro post de Haversine con JS. No olvides que en este caso la salida está en metros.
Usando Semiverseno con MySQL usando tabla
A continuación se presenta un ejemplo de una consulta usando esta fórmula:
INSERT INTO
ubicaciones_conductores (
id_conductor, fecha,
latitud, longitud, precision_horizontal,
id_ruta_destino, id_ruta_origen,
id_parada_mas_cercana, distancia_parada_mas_cercana
)
SELECT ?, ?,
?, ?, ?,
?, ?,
subconsulta.id, subconsulta.distancia
FROM
(
SELECT
id,
haversine(latitud, longitud, ?, ?) AS distancia
FROM
paradas
ORDER BY
distancia ASC
LIMIT
1
) AS subconsulta;
Si quisieras un ejemplo más sencillo podrías hacer algo como:
SELECT haversine(lat1, lon1, lat2, lot2) AS distancia FROM tabla;