J'essaie de calculer la distance entre deux positions sur une carte. J'ai enregistré dans mes données: Longitude, Latitude, X POS, Y POS.
J'ai déjà utilisé l'extrait ci-dessous.
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
Cependant, je ne fais pas confiance aux données qui en résultent, cela semble donner des résultats légèrement inexacts.
Quelques exemples de données en cas de besoin
Latitude Longitude Distance
53.429108 -2.500953 85.2981833133896
Quelqu'un pourrait-il m'aider avec mon code, cela ne me dérange pas si vous voulez réparer ce que j'ai déjà si vous avez un nouveau moyen d'y parvenir, ce serait génial.
Veuillez indiquer dans quelle unité de mesure vos résultats sont exprimés.
Puisque vous utilisez SQL Server 2008, vous disposez du type de données geography
, qui est conçu pour ce type de données:
DECLARE @source geography = 'POINT(0 51.5)'
DECLARE @target geography = 'POINT(-3 56)'
SELECT @source.STDistance(@target)
Donne
----------------------
538404.100197555
(1 row(s) affected)
En nous disant que c'est environ 538 km de (proche) Londres à (près) Edimbourg.
Naturellement, vous devrez d'abord apprendre beaucoup de choses à faire, mais une fois que vous le savez, c'est beaucoup plus facile que de mettre en œuvre votre propre calcul Haversine; De plus, vous obtenez BEAUCOUP de fonctionnalités.
Si vous souhaitez conserver votre structure de données existante, vous pouvez toujours utiliser STDistance
en construisant des instances appropriées de geography
à l'aide de la méthode 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 fonction ci-dessous donne distance entre deux coordonnées géographiques en miles
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 fonction ci-dessous donne distance entre deux coordonnées géographiques en kilomètres
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 fonction ci-dessous donne distance entre deux coordonnées géographiques en kilomètres en utilisant Géographie type de données introduit dans SQL Server 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);
sage:
select [dbo].[fnCalcDistanceKM](13.077085,80.262675,13.065701,80.258916)
Il semble que Microsoft ait envahi le cerveau de tous les autres répondants et leur ait fait écrire des solutions aussi compliquées que possible. Voici le moyen le plus simple, sans aucune fonction/déclaration supplémentaire:
SELECT geography::Point(LATITUDE_1, LONGITUDE_1, 4326).STDistance(geography::Point(LATITUDE_2, LONGITUDE_2, 4326))
Remplacez simplement vos données au lieu de LATITUDE_1
, LONGITUDE_1
, LATITUDE_2
, LONGITUDE_2
par exemple:
SELECT geography::Point(53.429108, -2.500953, 4326).STDistance(geography::Point(c.Latitude, c.Longitude, 4326))
from coordinates c
Si vous utilisez SQL 2008 ou une version ultérieure, je vous recommande de vérifier le type de données GEOGRAPHY . SQL prend en charge les requêtes géospatiales.
par exemple. vous auriez une colonne de type GEOGRAPHY dans votre table qui serait peuplée d'une représentation géospatiale des coordonnées (consultez la référence MSDN liée ci-dessus pour des exemples). Ce type de données expose ensuite des méthodes vous permettant d'effectuer toute une série de requêtes géospatiales (par exemple, déterminer la distance entre 2 points).
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
tilisation:
sélectionnez dbo.DistanceKM (37.848832506474, 37.848732506474, 27.83935546875, 27.83905546875)
Sorties:
0,02849639
Vous pouvez modifier le paramètre @R avec des flotteurs commentés.
En plus des réponses précédentes, voici un moyen de calculer la distance à l’intérieur d’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
Usage:
select Distance
from Place P1,
Place P2,
outer apply dbo.Get_Distance(P1.latitude, P1.longitude, P2.latitude, P2.longitude)
Les fonctions scalaires fonctionnent également, mais elles sont très inefficaces pour le traitement de grandes quantités de données.
J'espère que cela pourrait aider quelqu'un.