sql - metros - Cálculo de distancia entre dos puntos(Latitud, Longitud)
formula de haversine (6)
Estoy tratando de calcular la distancia entre dos posiciones en un mapa. He almacenado mis datos: longitud, latitud, X POS, Y POS.
He estado usando el fragmento de abajo a continuación.
DECLARE @orig_lat DECIMAL
DECLARE @orig_lng DECIMAL
SET @orig_lat=53.381538 set @orig_lng=-1.463526
SELECT *,
3956 * 2 * ASIN(
SQRT( POWER(SIN((@orig_lat - abs(dest.Latitude)) * pi()/180 / 2), 2)
+ COS(@orig_lng * pi()/180 ) * COS(abs(dest.Latitude) * pi()/180)
* POWER(SIN((@orig_lng - dest.Longitude) * pi()/180 / 2), 2) ))
AS distance
--INTO #includeDistances
FROM #orig dest
Sin embargo, no confío en los datos que surgen de esto, parece dar resultados ligeramente inexactos.
Algunos datos de muestra en caso de que lo necesite
Latitude Longitude Distance
53.429108 -2.500953 85.2981833133896
¿Alguien podría ayudarme con mi código, no me importa si quieres arreglar lo que ya tengo si tienes una nueva forma de lograr esto que sería genial.
Indique en qué unidad de medida se encuentran sus resultados.
Además de las respuestas anteriores, aquí hay una forma de calcular la distancia dentro de un SELECT:
CREATE FUNCTION Get_Distance
(
@La1 float , @Lo1 float , @La2 float, @Lo2 float
)
RETURNS TABLE
AS
RETURN
-- Distance in Meters
SELECT GEOGRAPHY::Point(@La1, @Lo1, 4326).STDistance(GEOGRAPHY::Point(@La2, @Lo2, 4326))
AS Distance
GO
Uso:
select Distance
from Place P1,
Place P2,
outer apply dbo.Get_Distance(P1.latitude, P1.longitude, P2.latitude, P2.longitude)
Las funciones escalares también funcionan pero son muy ineficientes cuando se computan grandes cantidades de datos.
Espero que esto pueda ayudar a alguien.
Como está utilizando SQL 2008 o posterior, le recomiendo consultar el tipo de datos geography . SQL ha incorporado soporte para consultas geoespaciales.
por ejemplo, tendría una columna en su tabla de tipo GEOGRAPHY que se llenaría con una representación geoespacial de las coordenadas (consulte la referencia de MSDN vinculada anteriormente para ver ejemplos). Este tipo de datos luego expone los métodos que le permiten realizar una gran cantidad de consultas geoespaciales (por ejemplo, encontrar la distancia entre 2 puntos)
Dado que está utilizando SQL Server 2008, tiene el tipo de datos de geography
disponible, que está diseñado para exactamente este tipo de datos:
DECLARE @source geography = ''POINT(0 51.5)''
DECLARE @target geography = ''POINT(-3 56)''
SELECT @source.STDistance(@target)
Da
----------------------
538404.100197555
(1 row(s) affected)
Indicarnos que está a unos 538 km de (cerca de Londres) a (cerca) Edimburgo.
Naturalmente, habrá una cantidad de aprendizaje que hacer primero, pero una vez que lo sepa, es mucho más fácil que implementar su propio cálculo de Haversine; además obtienes MUCHA funcionalidad.
Si desea conservar su estructura de datos existente, aún puede usar STDistance
, mediante la construcción de instancias de geography
adecuadas utilizando el método Point
:
DECLARE @orig_lat DECIMAL(12, 9)
DECLARE @orig_lng DECIMAL(12, 9)
SET @orig_lat=53.381538 set @orig_lng=-1.463526
DECLARE @orig geography = geography::Point(@orig_lat, @orig_lng, 4326);
SELECT *,
@orig.STDistance(geography::Point(dest.Latitude, dest.Longitude, 4326))
AS distance
--INTO #includeDistances
FROM #orig dest
La función siguiente proporciona la distancia entre dos coordenadas geográficas en millas
create function [dbo].[fnCalcDistanceMiles] (@Lat1 decimal(8,4), @Long1 decimal(8,4), @Lat2 decimal(8,4), @Long2 decimal(8,4))
returns decimal (8,4) as
begin
declare @d decimal(28,10)
-- Convert to radians
set @Lat1 = @Lat1 / 57.2958
set @Long1 = @Long1 / 57.2958
set @Lat2 = @Lat2 / 57.2958
set @Long2 = @Long2 / 57.2958
-- Calc distance
set @d = (Sin(@Lat1) * Sin(@Lat2)) + (Cos(@Lat1) * Cos(@Lat2) * Cos(@Long2 - @Long1))
-- Convert to miles
if @d <> 0
begin
set @d = 3958.75 * Atan(Sqrt(1 - power(@d, 2)) / @d);
end
return @d
end
La función siguiente proporciona la distancia entre dos coordenadas geográficas en kilómetros
CREATE FUNCTION dbo.fnCalcDistanceKM(@lat1 FLOAT, @lat2 FLOAT, @lon1 FLOAT, @lon2 FLOAT)
RETURNS FLOAT
AS
BEGIN
RETURN ACOS(SIN(PI()*@lat1/180.0)*SIN(PI()*@lat2/180.0)+COS(PI()*@lat1/180.0)*COS(PI()*@lat2/180.0)*COS(PI()*@lon2/180.0-PI()*@lon1/180.0))*6371
END
La función siguiente proporciona la distancia entre dos coordenadas geográficas en kilómetros utilizando el tipo de datos geography que se introdujo en el servidor sql 2008
DECLARE @g geography;
DECLARE @h geography;
SET @g = geography::STGeomFromText(''LINESTRING(-122.360 47.656, -122.343 47.656)'', 4326);
SET @h = geography::STGeomFromText(''POINT(-122.34900 47.65100)'', 4326);
SELECT @g.STDistance(@h);
Uso:
select [dbo].[fnCalcDistanceKM](13.077085,80.262675,13.065701,80.258916)
Referencia: Ref1 , Ref2
Parece que Microsoft invadió los cerebros de todos los demás encuestados y les hizo escribir soluciones tan complicadas como sea posible. Esta es la forma más simple sin ninguna función adicional / declaraciones declare:
SELECT geography::Point(LATITUDE_1, LONGITUDE_1, 4326).STDistance(geography::Point(LATITUDE_2, LONGITUDE_2, 4326))
Simplemente sustituya sus datos en lugar de LATITUDE_1
, LONGITUDE_1
, LATITUDE_2
, LONGITUDE_2
, por ejemplo:
SELECT geography::Point(53.429108, -2.500953, 4326).STDistance(geography::Point(c.Latitude, c.Longitude, 4326))
from coordinates c
Create Function [dbo].[DistanceKM]
(
@Lat1 Float(18),
@Lat2 Float(18),
@Long1 Float(18),
@Long2 Float(18)
)
Returns Float(18)
AS
Begin
Declare @R Float(8);
Declare @dLat Float(18);
Declare @dLon Float(18);
Declare @a Float(18);
Declare @c Float(18);
Declare @d Float(18);
Set @R = 6367.45
--Miles 3956.55
--Kilometers 6367.45
--Feet 20890584
--Meters 6367450
Set @dLat = Radians(@lat2 - @lat1);
Set @dLon = Radians(@long2 - @long1);
Set @a = Sin(@dLat / 2)
* Sin(@dLat / 2)
+ Cos(Radians(@lat1))
* Cos(Radians(@lat2))
* Sin(@dLon / 2)
* Sin(@dLon / 2);
Set @c = 2 * Asin(Min(Sqrt(@a)));
Set @d = @R * @c;
Return @d;
End
GO
Uso:
seleccione dbo.DistanceKM (37.848832506474, 37.848732506474, 27.83935546875, 27.83905546875)
Productos:
0,02849639
Puede cambiar el parámetro @R con flotadores comentados.