Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Ottieni la longitudine e la latitudine più vicine dalla tabella del database MSSQL?

Diamo un'occhiata a un semplice esempio di utilizzo di STDistance funzione in SQL Server 2008 (e versioni successive).

Dirò a SQL Server che sono a Londra e voglio vedere quanto sono lontani i miei uffici. Ecco i risultati che voglio che SQL Server mi dia:

Innanzitutto, avremo bisogno di alcuni dati di esempio. Creeremo una tabella contenente alcune posizioni degli uffici Microsoft e memorizzeremo i loro valori di longitudine e latitudine in una geography campo.

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())

Ora, supponiamo di essere a Londra. Ecco come creare una geography valore fuori dai valori di longitudine e latitudine di Londra:

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) + ')';

E infine, vediamo quanto dista ciascuno dei nostri uffici.

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

E questo ci dà i risultati che speravamo.

Ovviamente potresti inserire un TOP(1) se vuoi solo vedere il più vicino ufficio.

Bello, ehi?

C'è solo un intoppo. Quando hai molta geography punti con cui confrontare, le prestazioni non sono eccezionali, anche se aggiungi un INDICE SPAZIALE su quel campo del database.

Ho testato un punto su una tabella di 330.000 geography punti. Utilizzando il codice mostrato qui, ha trovato il punto più vicino in circa 8 secondi .

Quando ho modificato la mia tabella per memorizzare i valori di longitudine e latitudine e ho utilizzato [dbo].[fnCalcDistanceMiles] funzione di questo articolo StackOverflow, ha trovato il punto più vicino in circa 3 secondi .

Comunque...

Tutti i campioni di "distanza tra due punti" che ho trovato su Internet utilizzavano SQL Server STDistance funzione o formule matematiche che coinvolgono le funzioni cos, sin e tan (con uso intensivo della CPU).

Una soluzione più rapida era viaggiare indietro nel tempo fino al liceo e ricordare come Pitagora calcolava la distanza tra due punti.

Supponiamo di voler conoscere la distanza tra Londra e Parigi.

Ed ecco la mia funzione di 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

Ora, ricorda che questa funzione non restituisce un valore in miglia, chilometri, ecc... sta semplicemente confrontando i valori di longitudine e latitudine. E Pitagora è pensato per essere utilizzato in 2D e non per confrontare punti su un pianeta rotondo!

Tuttavia, nei miei test, ha trovato il punto più vicino entro 1 secondo e ha prodotto gli stessi risultati dell'utilizzo di STDistance di SQL Server funzione.

Quindi, sentiti libero di usare questa funzione per confrontare le distanze relative , ma non utilizzare questa funzione se hai bisogno della distanza effettiva stessa.

Spero che tutto questo aiuti.