Jaki jest najlepszy sposób przechowywania współrzędnych (długość / szerokość geograficzna, z Google Maps) w SQL Server?


103

Projektuję tabelę w SQL Server 2008, która będzie przechowywać listę użytkowników i współrzędne Google Maps (długość i szerokość geograficzna).

Czy będę potrzebować dwóch pól, czy można to zrobić z 1?

Jaki jest najlepszy (lub najczęściej używany) typ danych do przechowywania tego rodzaju danych?

Odpowiedzi:



63

Uczciwe ostrzeżenie! Zanim skorzystasz z porady dotyczącej używania typu GEOGRAFIA, upewnij się, że nie planujesz używać Linq lub Entity Framework do uzyskiwania dostępu do danych, ponieważ nie są one obsługiwane (stan na listopad 2010) i będziesz smutny!

Zaktualizuj lipiec 2017

Dla tych, którzy czytają teraz tę odpowiedź, jest ona przestarzała, ponieważ odnosi się do stosu technologii przestarzałych. Więcej szczegółów w komentarzach.


1
Ponieważ opublikowano oryginalną odpowiedź, znalazłem ten artykuł jasonfollas.com/blog/archive/2010/02/14/ ... omawiający możliwe obejście.
Norman H,

56
Ostrzeżenie jest już nieaktualne. EF obsługuje teraz typy geograficzne.
Marcelo Mason

1
Beznerwowy EF obsługuje typy przestrzenne, używa innego typu ustawionego na usługi danych WCF, dlatego nie są kompatybilne
abatishchev

1
hibernacja 5 przestrzenna nadal nie działa na przykład :(
Eugene

1
Fair Warning nadal obowiązuje Entity Framework Core 2.0 github.com/aspnet/EntityFrameworkCore/issues/1100
ono2012

29

Nie znam odpowiedzi na SQL Server, ale ...

W MySQL zapisz go jakoFLOAT( 10, 6 )

To jest oficjalna rekomendacja z dokumentacji programistów Google .

CREATE TABLE `coords` (
  `lat` FLOAT( 10, 6 ) NOT NULL ,
  `lng` FLOAT( 10, 6 ) NOT NULL ,
) ENGINE = MYISAM ;

19
Pytanie jasno określa SQL Server, a nie MySQL. I na pewno nie chciałbyś stołu z taką samą szerokością i długością geograficzną.
araqnid

2
Zgoda - zła odpowiedź. Użyj nowego typu przestrzennego GEOGRAFIA.
Pure.Krome

2
Link również został przeniesiony na code.google.com/apis/maps/articles/phpsqlajax.html
Ralph Lavelle,

14
Nie użyłbym pływaka ze względu na problemy z precyzją. Użyj dziesiętnego (9,6).
kaptan

Istnieją przypadki, w których rzeczywiste lati lngDoskonałość georgraphy, nawet przy wysokiej gęstości indeksów w SQL 2014 na przykład: znaleźć wszystko punkt withing prostokąt. Tylko nie jestem pewien, widzę, że Mapy Google używają teraz 7 zamiast 6 cyfr?
Nenad

22

Sposób, w jaki to robię: przechowuję szerokość i długość geograficzną, a następnie mam trzecią kolumnę, która jest automatycznie wyprowadzonym typem geograficznym pierwszych dwóch kolumn. Tabela wygląda następująco:

CREATE TABLE [dbo].[Geopoint]
(
    [GeopointId] BIGINT NOT NULL PRIMARY KEY IDENTITY, 
    [Latitude] float NOT NULL, 
    [Longitude] float NOT NULL, 
    [ts] ROWVERSION NOT NULL, 
    [GeographyPoint]  AS ([geography]::STGeomFromText(((('POINT('+CONVERT([varchar](20),[Longitude]))+' ')+CONVERT([varchar](20),[Latitude]))+')',(4326))) 
)

Zapewnia to elastyczność zapytań przestrzennych w kolumnie geoPoint, a także umożliwia pobieranie wartości szerokości i długości geograficznej, gdy są potrzebne do wyświetlania lub wyodrębniania do celów CSV.


super jak na to, czego szukałem, czy masz coś na tory / linie
agresja

Innym podejściem, które również może zadziałać, w zależności od scenariusza, jest przechowywanie długich i szerokości geograficznych, a następnie dynamiczne tworzenie obiektu geograficznego w locie w czasie wykonywania.
Zapnologica

1
Świetny pomysł, ale pamiętaj, że nie możesz tworzyć indeksów przestrzennych na obliczanych kolumnach, jeśli jest to czyjś zamiar.
hvaughan3

1
@ hvaughan3 Myślę, że możesz, jeśli utworzysz trwałą kolumnę obliczeniową.
NickG,

2
Dzięki i +1, Twoja odpowiedź mi pomogła. Ale myślę, że lepiej byłoby użyć Pointzamiast STGeomFromText. Na przykład: [geography]::Point([Latitude], [Longitude], 4326).
default.kramer

21

Nienawidzę być przeciwieństwem tych, którzy mówili „oto nowy typ, użyjmy go”. Nowe typy przestrzenne SQL Server 2008 mają pewne zalety - mianowicie wydajność, jednak nie można ślepo powiedzieć, że zawsze używaj tego typu. To naprawdę zależy od większych problemów z obrazem.

Na przykład integracja. Ten typ ma równoważny typ w .Net - ale co z interopem? A co z obsługą lub rozszerzaniem starszych wersji .Net? A co z ujawnieniem tego typu w warstwie usług na innych platformach? A co z normalizacją danych - może interesuje Cię łata lub długa jako samodzielne informacje. Być może napisałeś już złożoną logikę biznesową do obsługi długich / lat.

Nie mówię, że nie powinieneś używać typu przestrzennego - w wielu przypadkach powinieneś. Mówię tylko, że powinieneś zadać bardziej krytyczne pytania, zanim pójdziesz tą ścieżką. Aby jak najdokładniej odpowiedzieć na Twoje pytanie, potrzebowałbym więcej informacji o Twojej konkretnej sytuacji.

Przechowywanie długich / szer. Osobno lub w typie przestrzennym jest dobrym rozwiązaniem i jedno może być lepsze od drugiego w zależności od twoich okoliczności.


GIS i przetwarzanie danych przestrzennych mają długą historię i standardowe reprezentacje tekstowe, binarne co najmniej od 2000 roku. Skończysz ze wszystkimi problemami, o których wspomniałeś, jeśli nie użyjesz typów przestrzennych i standardowych reprezentacji
Panagiotis Kanavos,

15

To, co chcesz zrobić, to zapisać szerokość i długość geograficzną jako nowy typ SQL2008 Spatial -> GEOGRAPHY.

Oto zrzut ekranu tabeli, którą mam.

tekst alternatywny http://img20.imageshack.us/img20/6839/zipcodetable.png

W tej tabeli mamy dwa pola, które przechowują dane geograficzne.

  • Granica: jest to wielokąt, który jest granicą kodu pocztowego
  • CentrePoint: jest to punkt szerokości / długości geograficznej, który reprezentuje wizualny środkowy punkt tego wielokąta.

Głównym powodem, dla którego chcesz zapisać go w bazie danych jako typ GEOGRAFII, jest to, że możesz następnie wykorzystać wszystkie metody PRZESTRZENNE -> np. Punkt w poli, odległość między dwoma punktami itp.

BTW, używamy również Google Maps API do pobierania danych o szerokości / długości i przechowywania ich w naszej bazie danych Sql 2008 - więc ta metoda działa.


1
A co, jeśli nie jesteś jeszcze w 2008 roku lub co, jeśli używasz SQLCE? Ten ostatni nie obsługuje typu GEOGRAFIA ...
fretje

3
Jeśli SqlCE lub <2008 obsługuje dane binarne, możliwe jest przechowywanie wyników w formacie varbinary, a następnie użycie biblioteki dll z biblioteką narzędzi przestrzennych do wykonywania obliczeń przestrzennych na tej reprezentacji danych binarnych w kodzie .NET. Nie jest to najlepsze rozwiązanie, ale wciąż możliwe rozwiązanie niektórych problemów. (NuGet dla sql spatial .. aby pobrać tę bibliotekę dll).
Pure.Krome

2
Link do obrazu jest uszkodzony
Bryan Denny

urgh :( dzięki za nic imageshack. Nie używałem IS od lat :( imgur.com cały czas!
Pure.Krome

1
-1, ta odpowiedź jest niekompletna bez obrazu. Rozważ zastąpienie go nowym obrazem lub tekstowym opisem tabeli albo usunięcie tej odpowiedzi.
Ilmari Karonen

11

SQL Server obsługuje informacje przestrzenne. Więcej informacji można znaleźć pod adresem http://www.microsoft.com/sqlserver/2008/en/us/spatial-data.aspx .

Alternatywnie możesz przechowywać informacje jako dwa podstawowe pola. Zwykle liczba zmiennoprzecinkowa jest standardowym typem danych zgłaszanych przez większość urządzeń i jest wystarczająco dokładna z dokładnością do cala lub dwóch - więcej niż wystarczająca dla Map Google.


2

UWAGA : To jest ostatnia odpowiedź oparta na ostatnich aktualizacjach stosu SQL Server i .NET

szerokość geograficzna i długość geograficzna z Google Maps powinny być przechowywane jako dane Point (uwaga duże P) na serwerze SQL w ramach typu danych geograficznych.

Zakładając, że twoje bieżące dane są przechowywane w tabeli Samplejako varchar pod kolumnami, lata lonponiższe zapytanie pomoże ci przekonwertować na geografię

alter table Sample add latlong geography
go
update Sample set latlong= geography::Point(lat,lon,4326)
go

PS: Następnym razem, gdy wybierzesz tę tabelę z danymi geograficznymi, oprócz zakładki Wyniki i wiadomości, otrzymasz również kartę Wyniki przestrzenne, jak poniżej, do wizualizacji

Karta wyników geograficznych SSMS


0

Jeśli używasz Entity Framework 5 <możesz użyć DbGeography. Przykład z MSDN:

public class University  
{ 
    public int UniversityID { get; set; } 
    public string Name { get; set; } 
    public DbGeography Location { get; set; } 
}

public partial class UniversityContext : DbContext 
{ 
    public DbSet<University> Universities { get; set; } 
}

using (var context = new UniversityContext ()) 
{ 
    context.Universities.Add(new University() 
        { 
            Name = "Graphic Design Institute", 
            Location = DbGeography.FromText("POINT(-122.336106 47.605049)"), 
        }); 

    context. Universities.Add(new University() 
        { 
            Name = "School of Fine Art", 
            Location = DbGeography.FromText("POINT(-122.335197 47.646711)"), 
        }); 

    context.SaveChanges(); 

    var myLocation = DbGeography.FromText("POINT(-122.296623 47.640405)"); 

    var university = (from u in context.Universities 
                        orderby u.Location.Distance(myLocation) 
                        select u).FirstOrDefault(); 

    Console.WriteLine( 
        "The closest University to you is: {0}.", 
        university.Name); 
}

https://msdn.microsoft.com/en-us/library/hh859721(v=vs.113).aspx

Coś, z czym walczyłem, a potem zacząłem używać, DbGeographyto coordinateSystemId. Zobacz odpowiedź poniżej, aby uzyskać doskonałe wyjaśnienie i źródło poniższego kodu.

public class GeoHelper
{
    public const int SridGoogleMaps = 4326;
    public const int SridCustomMap = 3857;

    public static DbGeography FromLatLng(double lat, double lng)
    {
        return DbGeography.PointFromText(
            "POINT("
            + lng.ToString() + " "
            + lat.ToString() + ")",
            SridGoogleMaps);
    }
}

https://stackoverflow.com/a/25563269/3850405


-4

Jeśli zamierzasz zamienić go na adres URL, przypuszczam, że wystarczy jedno pole - możesz więc utworzyć adres URL podobny do

http://maps.google.co.uk/maps?q=12.345678,12.345678&z=6

ale ponieważ są to dwie części danych, przechowywałbym je w osobnych polach


To moja sprawa. Muszę przechowywać współrzędne tylko w jednym polu i oddzielone przecinkiem. Myślę, że można użyć TEKSTU jako typu pola. Co myślisz?
Amr

-10

Przechowuj oba jako zmiennoprzecinkowe i używaj na nich unikalnych słów kluczowych

create table coordinates(
coord_uid counter primary key,
latitude float,
longitude float,
constraint la_long unique(latitude, longitude)
);

Aby upewnić się, że istnieje tylko jeden unikalny zestaw par szerokości i długości geograficznej. Nie chcesz dwukrotnie przechowywać współrzędnych {0,0} w swojej tabeli, prawda?
Graviton

1
Prawdopodobnie w ogóle nie chcesz mieć oddzielnej tabeli współrzędnych, jak ta, zwłaszcza z ograniczeniem wyjątkowości, jest to koszmar konserwacji obsługujący przypadek, w którym dwie lokalizacje odnoszą się do tego samego punktu, nie wspominając o czyszczeniu wierszy bez odniesień.
araqnid

2
> Prawdopodobnie w ogóle nie chcesz mieć oddzielnej tabeli współrzędnych, takiej jak ta - Wcale nie? Nigdy? Jak byś to przechowywał w 1 polu? A co z milionami ludzi NIE używających typu SQL 2008 Spatial?
Sally

2
Posiadanie takiego ograniczenia to zła decyzja. Załóżmy, że Bob mieszka House A, i przeniesie się do House B, domu, w którym Alicja używane żyć. Wkrótce Bob nie będzie mógł zapisać swojego adresu (lokalizacji), ponieważ Alicja jeszcze nie zaktualizowała swojego adresu - lub nigdy tego nie zrobi.
jweyrich

@ Sally - nie to powiedział. Przeczytaj jego komentarz. Powiedział, że nie powinno być powodu, aby przechowywać parę wartości w osobnej tabeli . Po prostu umieść długość / szerokość geograficzną na oryginalnym stole i zachowaj narzut drugiego stołu i wszystkich JOINS.
NickG,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.