Was ist der beste Weg, um Koordinaten (Längen- / Breitengrad, aus Google Maps) in SQL Server zu speichern?

103

Ich entwerfe eine Tabelle in SQL Server 2008, in der eine Liste der Benutzer und eine Google Maps-Koordinate (Längen- und Breitengrad) gespeichert werden.

Benötige ich zwei Felder oder kann es mit 1 gemacht werden?

Was ist der beste (oder häufigste) Datentyp zum Speichern dieser Art von Daten?

Jonathan
quelle

Antworten:

63

Faire Warnung! Bevor Sie den Rat zur Verwendung des GEOGRAPHY-Typs befolgen, stellen Sie sicher, dass Sie nicht vorhaben, mit Linq oder Entity Framework auf die Daten zuzugreifen, da diese nicht unterstützt werden (Stand November 2010), und Sie werden traurig sein!

Update Jul 2017

Für diejenigen, die diese Antwort jetzt lesen, ist sie veraltet, da sie sich auf einen zurückdatierten Technologie-Stack bezieht. Weitere Details finden Sie in den Kommentaren.

dan90266
quelle
1
Da die ursprüngliche Antwort veröffentlicht wurde, fand ich diesen Artikel jasonfollas.com/blog/archive/2010/02/14/… , in dem eine mögliche Problemumgehung besprochen wurde .
Norman H
56
Warnung ist nicht mehr gültig. EF unterstützt jetzt Geografietypen.
Marcelo Mason
1
Nerveless EF unterstützt räumliche Typen, es verwendet einen anderen Typ, der auf WCF Data Services eingestellt ist, daher gibt es keine kompatiblen
abatishchev
1
Winterschlaf 5 räumlich nicht zum Beispiel :(
Eugene
1
Faire Warnung gilt weiterhin Entity Framework Core 2.0 github.com/aspnet/EntityFrameworkCore/issues/1100
ono2012
29

Ich kenne die Antwort für SQL Server nicht, aber ...

In MySQL speichern Sie es alsFLOAT( 10, 6 )

Dies ist die offizielle Empfehlung aus der Google-Entwicklerdokumentation .

CREATE TABLE `coords` (
  `lat` FLOAT( 10, 6 ) NOT NULL ,
  `lng` FLOAT( 10, 6 ) NOT NULL ,
) ENGINE = MYISAM ;
powtac
quelle
19
Die Frage besagt eindeutig SQL Server, nicht MySQL. Und so einen Tisch mit Längen- und Breitengrad würden Sie sicher nicht wollen.
Araqnid
2
Einverstanden - schlechte Antwort. Verwenden Sie den neuen räumlichen Typ GEOGRAPHIE.
Pure.Krome
2
Der Link wurde ebenfalls verschoben, um zu code.google.com/apis/maps/articles/phpsqlajax.html
Ralph Lavelle
14
Ich würde float wegen Präzisionsproblemen nicht verwenden. Verwenden Sie eine Dezimalstelle (9,6).
Kapan
Es gibt tatsächliche Fälle, in denen wo latund lngübertreffengeorgraphy auch bei hohen Dichte Indizes in SQL 2014. Zum Beispiel: Finden Sie alle Punkt ein Rechteck ist withing. Nur bin ich mir nicht sicher, ich sehe, dass Google Maps jetzt 7 statt 6 Ziffern verwendet?
Nenad
22

So mache ich das: Ich speichere den Breiten- und Längengrad und habe dann eine dritte Spalte, die ein automatisch abgeleiteter Geografietyp der ersten beiden Spalten ist. Der Tisch sieht so aus:

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

Dies gibt Ihnen die Flexibilität von räumlichen Abfragen in der geoPoint-Spalte und Sie können auch die Breiten- und Längengrade abrufen, wenn Sie sie zum Anzeigen oder Extrahieren für CSV-Zwecke benötigen.

jaxxbo
quelle
großartig für das, wonach ich gesucht habe, hast du irgendetwas für Tracks / Lines
Aggie
Ein anderer Ansatz, der je nach Szenario auch funktionieren könnte, besteht darin, Long und Lat zu speichern und das Geografieobjekt zur Laufzeit einfach dynamisch im laufenden Betrieb zu erstellen.
Zapnologica
1
Tolle Idee, aber beachten Sie, dass Sie keine räumlichen Indizes für berechnete Spalten erstellen können, wenn dies beabsichtigt ist.
hvaughan3
1
@ hvaughan3 Ich denke, Sie können, wenn Sie es zu einer persistierten berechneten Spalte machen.
NickG
2
Danke und +1, deine Antwort hat mir geholfen. Aber ich denke, es wäre besser, Pointstatt zu verwenden STGeomFromText. Zum Beispiel : [geography]::Point([Latitude], [Longitude], 4326).
default.kramer
21

Ich hasse es, ein Gegenspieler zu denen zu sein, die sagten "hier ist ein neuer Typ, lass es uns benutzen". Die neuen räumlichen SQL Server 2008-Typen haben einige Vorteile - nämlich die Effizienz. Sie können jedoch nicht blind sagen, dass Sie diesen Typ immer verwenden. Es hängt wirklich von einigen größeren Problemen ab.

Als Beispiel Integration. Dieser Typ hat einen äquivalenten Typ in .Net - aber was ist mit Interop? Was ist mit der Unterstützung oder Erweiterung älterer Versionen von .Net? Wie wäre es, diesen Typ über die Service-Schicht hinweg anderen Plattformen auszusetzen? Was ist mit der Normalisierung von Daten? Vielleicht interessieren Sie sich für lat oder long als eigenständige Informationen. Vielleicht haben Sie bereits eine komplexe Geschäftslogik für Long / Lat geschrieben.

Ich sage nicht, dass Sie den räumlichen Typ nicht verwenden sollten - in vielen Fällen sollten Sie. Ich sage nur, dass Sie einige kritischere Fragen stellen sollten, bevor Sie diesen Weg gehen. Damit ich Ihre Frage am genauesten beantworten kann, muss ich mehr über Ihre spezifische Situation wissen.

Long / Lat separat oder in einem räumlichen Typ zu speichern, sind beide praktikable Lösungen, und je nach Ihren eigenen Umständen kann eine der anderen vorzuziehen sein.

R. Lawson
quelle
GIS und Geodatenverarbeitung haben eine lange Geschichte und zumindest seit den 2000er Jahren standardmäßige binäre Textdarstellungen. Sie werden mit all den Problemen enden, die Sie erwähnt haben, wenn Sie nicht die räumlichen Typen und die Standarddarstellungen verwenden
Panagiotis Kanavos
15

Sie möchten den Breiten- und Längengrad als neuen SQL2008-Raumtyp -> GEOGRAPHIE speichern.

Hier ist ein Screenshot eines Tisches, den ich habe.

Alternativtext http://img20.imageshack.us/img20/6839/zipcodetable.png

In dieser Tabelle haben wir zwei Felder, in denen Geografiedaten gespeichert sind.

  • Grenze: Dies ist das Polygon, das die Postleitzahlgrenze darstellt
  • CentrePoint: Dies ist der Breiten- / Längengradpunkt, der den visuellen Mittelpunkt dieses Polygons darstellt.

Der Hauptgrund, warum Sie es als GEOGRAPHY-Typ in der Datenbank speichern möchten, besteht darin, dass Sie dann alle SPATIAL-Methoden nutzen können -> z. Punkt in Poly, Abstand zwischen zwei Punkten usw.

Übrigens verwenden wir auch die Google Maps-API, um Lat / Long-Daten abzurufen und diese in unserer SQL 2008-Datenbank zu speichern. Diese Methode funktioniert also.

Pure.Krome
quelle
1
Und was ist, wenn Sie noch nicht auf 2008 sind oder wenn Sie SQLCE verwenden? Letzterer unterstützt den Typ
GEOGRAPHY
3
Wenn SqlCE oder <2008 Binärdateien unterstützt, können Sie die Ergebnisse varbinär speichern und dann die DLL der Spatial Tools Library verwenden, um räumliche Berechnungen für diese Binärdatendarstellung in Ihrem .NET-Code durchzuführen. Nicht die beste Lösung, aber dennoch eine mögliche Lösung für einige Probleme. (Nuget für SQL Spatial .. um diese DLL zu greifen).
Pure.Krome
2
Bild Link ist kaputt
Bryan Denny
urgh :( danke für nichts imageshack. Ich habe IS seit Jahren nicht mehr benutzt :( imgur.com den ganzen Weg!
Pure.Krome
1
-1, diese Antwort ist ohne das Bild unvollständig. Bitte erwägen Sie, es durch ein neues Bild oder eine Beschreibung der Texttabelle zu ersetzen oder diese Antwort zu löschen.
Ilmari Karonen
11

SQL Server unterstützt räumliche Informationen. Weitere Informationen finden Sie unter http://www.microsoft.com/sqlserver/2008/en/us/spatial-data.aspx .

Alternativ können Sie die Informationen als zwei grundlegende Felder speichern. In der Regel ist ein Float der Standarddatentyp, der von den meisten Geräten gemeldet wird. Er ist genau genug für ein oder zwei Zoll - mehr als ausreichend für Google Maps.

Rosstified
quelle
2

ANMERKUNG : Dies ist eine aktuelle Antwort, die auf den neuesten .NET-Stack-Updates für SQL Server basiert

Latitut und Längengrad von Google Maps sollten als Punktdaten (Notizkapital P) in SQL Server unter dem Datentyp Geografie gespeichert werden.

In einer Tabelle Ihre aktuellen Daten Unter der Annahme , gespeichert Sampleals varchar unter Spalten latund lonunter Abfrage werden Ihnen helfen, Geographie konvertieren

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

PS: Wenn Sie das nächste Mal in dieser Tabelle Geografiedaten auswählen, wird neben der Registerkarte Ergebnisse und Nachrichten auch die Registerkarte Räumliche Ergebnisse wie unten zur Visualisierung angezeigt

Registerkarte SSMS-Geoergebnisse

DhruvJoshi
quelle
0

Wenn Sie Entity Framework 5 <verwenden, können Sie verwenden DbGeography. Beispiel aus 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

Etwas, mit dem ich zu kämpfen hatte, als ich anfing, es zu benutzen, DbGeographywar das coordinateSystemId. In der Antwort unten finden Sie eine hervorragende Erklärung und Quelle für den folgenden Code.

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

Ogglas
quelle
-4

Wenn Sie es nur durch eine URL ersetzen möchten, reicht vermutlich ein Feld aus - Sie können also eine URL wie diese erstellen

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

Da es sich jedoch um zwei Daten handelt, würde ich sie in separaten Feldern speichern

Kristen
quelle
Das ist mein Fall. Ich muss die Koordinaten nur in einem Feld speichern und durch ein Komma trennen. Ich denke, man könnte einen TEXT als Feldtyp verwenden. Was denken Sie?
Amr
-10

Speichern Sie beide als float und verwenden Sie eindeutige Schlüsselwörter für them.i.em

create table coordinates(
coord_uid counter primary key,
latitude float,
longitude float,
constraint la_long unique(latitude, longitude)
);
Graviton
quelle
Um sicherzustellen, dass es nur einen eindeutigen Satz von Längen- und Breitengraden gibt. Sie möchten die Koordinate {0,0} nicht zweimal in Ihrer Tabelle speichern, nicht wahr?
Graviton
1
Sie möchten wahrscheinlich überhaupt keine separate Koordinatentabelle wie diese haben, insbesondere mit der Einschränkung der Eindeutigkeit, dass es sich um einen Alptraum für die Wartung handelt, wenn zwei Standorte auf denselben Punkt verweisen, ganz zu schweigen von der Bereinigung nicht referenzierter Zeilen.
Araqnid
2
> Sie möchten wahrscheinlich überhaupt keine separate Koordinatentabelle wie diese haben - überhaupt nicht? Noch nie? Wie würden Sie das in 1 Feld speichern? Was ist mit den Millionen von Menschen, die den SQL 2008 Spatial-Typ NICHT verwenden?
Sally
2
Eine solche Einschränkung zu haben, ist eine schlechte Entscheidung. Angenommen, Bob lebt in dem Haus, in dem Alice früher gelebt hat House A, und zieht House Bin dieses um. Bald wird Bob seine Adresse (Ort) nicht mehr speichern können, da Alice ihre noch nicht aktualisiert hat - oder nie aktualisieren wird.
Jweyrich
@ Sally - das hat er nicht gesagt. Lesen Sie seinen Kommentar. Er sagte, es sollte keinen Grund geben, ein Wertepaar in einer separaten Tabelle zu speichern . Legen Sie einfach das Lat / Long auf den Originaltisch und sparen Sie den Overhead eines zweiten Tisches und aller JOINS.
NickG