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

Obtenir la longitude et la latitude les plus proches de la table de base de données MSSQL ?

Regardons un exemple simple d'utilisation de la STDistance fonction dans SQL Server 2008 (et versions ultérieures).

Je vais dire à SQL Server que je suis à Londres et que je veux voir à quelle distance se trouvent chacun de mes bureaux. Voici les résultats que je veux que SQL Server me donne :

Tout d'abord, nous aurons besoin de quelques exemples de données. Nous allons créer une table contenant quelques emplacements de bureaux Microsoft, et nous stockerons leurs valeurs de longitude et de latitude dans une geography champ.

CREATE TABLE [Offices] (
    [Office_Id] [int] IDENTITY(1, 1) NOT NULL,
    [Office_Name] [nvarchar](200) NOT NULL,
    [Office_Location] [geography] NOT NULL,
    [Update_By] nvarchar(30) NULL,
    [Update_Time] [datetime]
) ON [PRIMARY]

GO

INSERT INTO [dbo].[Offices] VALUES ('Microsoft Zurich', 'POINT(8.590847 47.408860 )', 'mike', GetDate())
INSERT INTO [dbo].[Offices] VALUES ('Microsoft San Francisco', 'POINT(-122.403697 37.792062 )', 'mike', GetDate())
INSERT INTO [dbo].[Offices] VALUES ('Microsoft Paris', 'POINT(2.265509 48.833946)', 'mike', GetDate())
INSERT INTO [dbo].[Offices] VALUES ('Microsoft Sydney', 'POINT(151.138378 -33.796572)', 'mike', GetDate())
INSERT INTO [dbo].[Offices] VALUES ('Microsoft Dubai', 'POINT(55.286282 25.228850)', 'mike', GetDate())

Maintenant, supposons que nous étions à Londres. Voici comment créer une geography valeur parmi les valeurs de longitude et de latitude de Londres :

DECLARE 
    @latitude numeric(12, 7),
    @longitude numeric(12, 7)

SET @latitude = 51.507351
SET @longitude = -0.127758

DECLARE @g geography = 'POINT(' + cast(@longitude as nvarchar) + ' ' + cast(@latitude as nvarchar) + ')';

Et enfin, voyons à quelle distance chacun de nos bureaux se trouve.

SELECT [Office_Name], 
       cast([Office_Location].STDistance(@g) / 1609.344 as numeric(10, 1)) as 'Distance (in miles)' 
FROM [Offices]
ORDER BY 2 ASC

Et cela nous donne les résultats que nous espérions.

Évidemment, vous pourriez glisser un TOP(1) si vous vouliez juste voir le plus proche bureau.

Cool, hein ?

Il y a juste un hic. Lorsque vous avez beaucoup de geography points de comparaison, les performances ne sont pas brillantes, même si vous ajoutez un INDEX SPATIAL sur ce champ de base de données.

J'ai testé un point sur un tableau de 330 000 geography points. En utilisant le code affiché ici, il a trouvé le point le plus proche en environ 8 secondes .

Lorsque j'ai modifié ma table pour stocker les valeurs de longitude et de latitude et utilisé le [dbo].[fnCalcDistanceMiles] fonction de cet article StackOverflow, il a trouvé le point le plus proche en environ 3 secondes .

Cependant...

Tous les exemples de "distance entre deux points" que j'ai trouvés sur Internet utilisaient soit SQL Server STDistance ou des formules mathématiques impliquant les fonctions cos, sin et tan (qui sollicitent beaucoup le processeur).

Une solution plus rapide consistait à voyager dans le temps jusqu'au lycée et à se rappeler comment Pythagore calculait la distance entre deux points.

Supposons que nous voulions connaître la distance entre Londres et Paris.

Et voici ma fonction SQL Server :

CREATE FUNCTION [dbo].[uf_CalculateDistance] (@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)

    SET @d = sqrt(square(@[email protected]) + square(@[email protected]))

    RETURN @d
END

Maintenant, rappelez-vous que cette fonction ne renvoie pas de valeur en miles, kilomètres, etc., elle compare simplement les valeurs de longitude et de latitude. Et Pythagore est fait pour être utilisé en 2D, et non pour comparer des points sur une planète ronde !

Cependant, lors de mes tests, il a trouvé le point le plus proche en 1 seconde , et produit les mêmes résultats que l'utilisation de STDistance de SQL Server fonction.

N'hésitez donc pas à utiliser cette fonction pour comparer les distances relatives , mais n'utilisez pas cette fonction si vous avez besoin de la distance réelle elle-même.

J'espère que tout cela vous aidera.