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.