sql >> Databasteknik >  >> RDS >> Sqlserver

Få närmaste longitud och latitud från MSSQL-databastabellen?

Låt oss titta på ett enkelt exempel på hur du använder STDistance funktion i SQL Server 2008 (och senare).

Jag ska berätta för SQL Server att jag är i London, och jag vill se hur långt bort vart och ett av mina kontor är. Här är resultaten som jag vill att SQL Server ska ge mig:

Först behöver vi lite exempeldata. Vi skapar en tabell som innehåller några platser för Microsoft-kontor, och vi lagrar deras longitud- och latitudvärden i en geography fältet.

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

Om vi ​​nu var i London. Så här gör du en geography värde av Londons longitud- och latitudvärden:

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

Och slutligen, låt oss se hur långt vart och ett av våra kontor är.

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

Och detta ger oss de resultat vi hoppades på.

Självklart kan du lägga in en TOP(1) om du bara ville se de närmaste kontor.

Coolt, hej?

Det finns bara en hake. När du har mycket geography poäng att jämföra med, prestanda är inte lysande, även om du lägger till ett SPATIAL INDEX i det databasfältet.

Jag testade en punkt mot en tabell med 330 000 geography poäng. Med hjälp av koden som visas här hittade den den närmaste punkten på cirka 8 sekunder .

När jag ändrade min tabell för att lagra longitud- och latitudvärden och använde [dbo].[fnCalcDistanceMiles] från den här StackOverflow-artikeln hittade den den närmaste punkten på ungefär 3 sekunder .

Men...

Alla "avstånd mellan två punkter"-exempel jag hittade på internet använde antingen SQL Server STDistance funktion, eller matematiska formler som involverar de (CPU-intensiva) funktionerna cos, sin och tan.

En snabbare lösning var att resa tillbaka i tiden till gymnasiet och komma ihåg hur Pythagoras beräknade avståndet mellan två punkter.

Tänk om vi ville veta avståndet mellan London och Paris.

Och här är min SQL Server-funktion:

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

Kom nu ihåg att den här funktionen inte returnerar ett värde i miles, kilometer, etc... den jämför bara longitud- och latitudvärdena. Och Pythagoras är tänkt att användas i 2D, och inte att jämföra punkter på en rund planet!

Men i mina tester hittade den den närmaste punkten inom 1 sekund , och gav samma resultat som att använda SQL Servers STDistance funktion.

Så använd gärna den här funktionen för att jämföra relativa avstånd , men använd inte den här funktionen om du behöver själva avståndet.

Hoppas allt detta hjälper.



  1. Skickar array till Oracle-proceduren från c#

  2. Ansluter RazorSQL till Salesforce.com

  3. Oracle REGEXP_LIKE och ordgränser

  4. Kopiera data till ny tabell i MySQL