Qual è il modo migliore per memorizzare le coordinate (longitudine / latitudine, da Google Maps) in SQL Server?


103

Sto progettando una tabella in SQL Server 2008 che memorizzerà un elenco di utenti e una coordinata di Google Maps (longitudine e latitudine).

Avrò bisogno di due campi o posso farlo con 1?

Qual è il tipo di dati migliore (o più comune) da utilizzare per archiviare questo tipo di dati?

Risposte:



63

Giusto avvertimento! Prima di prendere il consiglio di utilizzare il tipo GEOGRAFIA, assicurati di non aver intenzione di utilizzare Linq o Entity Framework per accedere ai dati perché non è supportato (a partire da novembre 2010) e sarai triste!

Aggiornamento luglio 2017

Per coloro che leggono questa risposta ora, è obsoleta in quanto si riferisce allo stack tecnologico retrodatato. Vedere i commenti per maggiori dettagli.


1
Poiché è stata pubblicata la risposta originale, ho trovato questo articolo jasonfollas.com/blog/archive/2010/02/14/… che discuteva di una possibile soluzione alternativa.
Norman H

56
L'avviso non è più valido. EF ora supporta i tipi di geografia.
Marcelo Mason

1
Nerveless EF supporta i tipi spaziali, utilizza tipi diversi impostati su WCF Data Services, quindi non sono compatibili
abatishchev

1
ibernazione 5 spaziale non funziona ancora, ad esempio :(
Eugene

1
Fair Warning si applica ancora Entity Framework Core 2.0 github.com/aspnet/EntityFrameworkCore/issues/1100
ono2012

29

Non conosco la risposta per SQL Server ma ...

In MySQL salvalo comeFLOAT( 10, 6 )

Questa è la raccomandazione ufficiale dalla documentazione per sviluppatori di Google .

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

19
La domanda afferma chiaramente SQL Server, non MySQL. E di certo non vorresti un tavolo con solo latitudine e longitudine come quello.
araqnid

2
D'accordo - cattiva risposta. Usa il nuovo tipo spaziale GEOGRAFIA.
Pure.Krome

2
Anche il collegamento è stato spostato a code.google.com/apis/maps/articles/phpsqlajax.html
Ralph Lavelle

14
Non userei il float a causa di problemi di precisione. Usa decimale (9,6).
kaptan

Ci sono casi reali in cui dove late lngsovraperformano georgraphy, anche con indici ad alta densità in SQL 2014. Ad esempio: trova tutti i punti all'interno di un rettangolo. Solo che non sono sicuro, vedo che Google Maps ora usa 7 invece di 6 cifre?
Nenad

22

Il modo in cui lo faccio: memorizzo la latitudine e la longitudine e poi ho una terza colonna che è un tipo di geografia derivata automaticamente dalle prime due colonne. La tabella ha questo aspetto:

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

Ciò ti offre la flessibilità delle query spaziali sulla colonna geoPoint e puoi anche recuperare i valori di latitudine e longitudine quando ne hai bisogno per la visualizzazione o l'estrazione per scopi CSV.


ottimo per quello che stavo cercando, hai qualcosa per tracce / linee
aggie

Un altro approccio che potrebbe funzionare, a seconda del tuo scenario, consiste nell'archiviare long e lat, e quindi creare dinamicamente l'oggetto geography al volo in fase di esecuzione.
Zapnologica

1
Ottima idea, ma tieni presente che non puoi creare indici spaziali su colonne calcolate se questa è l'intenzione di qualcuno.
hvaughan3

1
@ hvaughan3 Penso che tu possa farlo se ne fai una colonna calcolata persistente .
NickG

2
Grazie e +1, la tua risposta mi ha aiutato. Ma penso che sarebbe meglio usare al Pointposto di STGeomFromText. Ad esempio: [geography]::Point([Latitude], [Longitude], 4326).
default.kramer

21

Odio essere contrarian a coloro che hanno detto "ecco un nuovo tipo, usiamolo". I nuovi tipi spaziali di SQL Server 2008 hanno alcuni vantaggi, ovvero l'efficienza, tuttavia non si può dire ciecamente di utilizzare sempre quel tipo. Dipende davvero da alcuni problemi di quadro più ampio.

Ad esempio, l'integrazione. Questo tipo ha un tipo equivalente in .Net, ma per quanto riguarda l'interoperabilità? Che dire del supporto o dell'estensione delle versioni precedenti di .Net? Che ne dici di esporre questo tipo attraverso il livello di servizio ad altre piattaforme? Che dire della normalizzazione dei dati, forse sei interessato a informazioni lat o long come informazioni autonome. Forse hai già scritto una logica di business complessa per gestire long / lat.

Non sto dicendo che non dovresti usare il tipo spaziale - in molti casi dovresti. Sto solo dicendo che dovresti porre alcune domande più critiche prima di intraprendere quella strada. Per poter rispondere alla tua domanda in modo più accurato, avrei bisogno di saperne di più sulla tua situazione specifica.

La memorizzazione di long / lat separatamente o in un tipo spaziale sono entrambe soluzioni praticabili e una può essere preferibile all'altra a seconda delle circostanze.


GIS e l'elaborazione dei dati spaziali hanno una lunga storia e rappresentazioni binarie testuali standard almeno dagli anni 2000. Ti ritroverai con tutti i problemi che hai menzionato se non usi i tipi spaziali e le rappresentazioni standard
Panagiotis Kanavos

15

Quello che vuoi fare è memorizzare la latitudine e la longitudine come nuovo tipo spaziale SQL2008 -> GEOGRAFIA.

Ecco una schermata di un tavolo, che ho.

testo alternativo http://img20.imageshack.us/img20/6839/zipcodetable.png

In questa tabella sono presenti due campi che memorizzano i dati geografici.

  • Confine: questo è il poligono che è il confine del codice postale
  • CentrePoint: questo è il punto di latitudine / longitudine che rappresenta il punto medio visivo di questo poligono.

Il motivo principale per cui vuoi salvarlo nel database come tipo GEOGRAFIA è che puoi quindi sfruttare tutti i metodi SPAZIALI fuori di esso -> es. Punto in poli, distanza tra due punti, ecc.

A proposito, utilizziamo anche l'API di Google Maps per recuperare i dati latitudine / longitudine e archiviarli nel nostro database SQL 2008, quindi questo metodo funziona.


1
E se non sei ancora nel 2008 o se usi SQLCE? Quest'ultimo non supporta il tipo GEOGRAFIA ...
fretje

3
Se SqlCE o <2008 supportano il binario, è possibile memorizzare i risultati sono varbinary e quindi utilizzare la dll della libreria degli strumenti spaziali per eseguire calcoli spaziali rispetto a questa rappresentazione di dati binari nel codice .NET. Non la soluzione migliore, ma comunque una possibile soluzione ad alcuni problemi. (nuget per sql spatial .. per afferrare quella dll).
Pure.Krome

2
Il collegamento dell'immagine è interrotto
Bryan Denny

urgh :( grazie per niente imageshack. Non uso IS da anni :( imgur.com fino in fondo!
Pure.Krome

1
-1, questa risposta è incompleta senza l'immagine. Considera la possibilità di sostituirlo con una nuova immagine o una descrizione di tabella testuale o di eliminare questa risposta.
Ilmari Karonen

11

SQL Server supporta le informazioni relative allo spazio. Puoi vedere di più su http://www.microsoft.com/sqlserver/2008/en/us/spatial-data.aspx .

In alternativa, puoi memorizzare le informazioni come due campi di base, di solito un float è il tipo di dati standard riportato dalla maggior parte dei dispositivi ed è abbastanza preciso per uno o due pollici, più che adeguato per Google Maps.


2

NOTA : questa è una risposta recente basata sui recenti aggiornamenti dello stack .NET di SQL Server

latitudine e longitudine da Google Maps devono essere archiviate come dati Point (nota P maiuscola) nel server SQL sotto il tipo di dati geography.

Supponendo che i tuoi dati correnti siano archiviati in una tabella Samplecome varchar sotto le colonne late lon, sotto la query, ti aiuterà a convertirti in geografia

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

PS: la prossima volta che esegui una selezione su questa tabella con i dati geografici, oltre alla scheda Risultati e Messaggi, otterrai anche la scheda Risultati spaziali come di seguito per la visualizzazione

Scheda risultati geografici SSMS


0

Se stai usando Entity Framework 5 <puoi usare DbGeography. Esempio da 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

Qualcosa con cui ho lottato quando ho iniziato a usare è DbGeographystato il file coordinateSystemId. Vedere la risposta di seguito per un'eccellente spiegazione e fonte per il codice sottostante.

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

Se hai intenzione di sostituirlo in un URL, suppongo che un campo andrebbe bene, quindi puoi formare un URL come

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

ma poiché sono due pezzi di dati, li memorizzerei in campi separati


Questo è il mio caso. Devo memorizzare le coordinate in un solo campo e separate da una virgola. Penso che si potrebbe usare un TESTO come tipo di campo. Cosa ne pensi?
Amr

-10

Memorizzali entrambi come float e usa parole chiave univoche su them.i.em

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

Per assicurarti che ci sia solo 1 set univoco di coppie di latitudine e longitudine. Non vuoi memorizzare le coordinate {0,0} due volte nella tua tabella, vero?
Graviton

1
Probabilmente non vuoi affatto avere una tabella di coordinate separata come questa, specialmente con il vincolo di unicità che è un incubo di manutenzione gestire il caso in cui due posizioni si riferiscono allo stesso punto, per non parlare della pulizia delle righe non referenziate.
araqnid

2
> Probabilmente non vuoi affatto avere una tabella di coordinate separata come questa - Niente affatto? Mai? Come lo immagazzineresti in 1 campo? E i milioni di persone che NON utilizzano il tipo spaziale SQL 2008?
Sally

2
Avere un tale vincolo è una cattiva decisione. Supponiamo che Bob viva House Ae si trasferisca House Bnella casa in cui viveva Alice. Presto Bob non sarà in grado di salvare il suo indirizzo (posizione), perché Alice non ha ancora aggiornato il suo, o non lo farà mai.
jweyrich

@ Sally - non è quello che ha detto. Leggi il suo commento. Ha detto che non dovrebbe esserci alcun motivo per memorizzare una coppia di valori in una tabella separata . Metti semplicemente lat / long sul tavolo originale e salva l'overhead di un secondo tavolo e tutti i JOINS.
NickG
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.