Quelle est la meilleure façon de stocker des coordonnées (longitude / latitude, à partir de Google Maps) dans SQL Server?

103

Je conçois une table dans SQL Server 2008 qui stockera une liste d'utilisateurs et une coordonnée Google Maps (longitude et latitude).

Aurai-je besoin de deux champs ou est-ce possible de le faire avec 1?

Quel est le type de données le meilleur (ou le plus courant) à utiliser pour stocker ce type de données?

Jonathan
la source

Réponses:

63

Avertissement juste! Avant de suivre les conseils pour utiliser le type GEOGRAPHY, assurez-vous que vous ne prévoyez pas d'utiliser Linq ou Entity Framework pour accéder aux données car il n'est pas pris en charge (à partir de novembre 2010) et vous serez triste!

Mise à jour juillet 2017

Pour ceux qui lisent cette réponse maintenant, elle est obsolète car elle fait référence à une pile technologique antidatée. Voir les commentaires pour plus de détails.

dan90266
la source
1
Depuis que la réponse originale a été publiée, j'ai trouvé cet article jasonfollas.com/blog/archive/2010/02/14/… discutant d'une solution de contournement possible.
Norman H
56
L'avertissement n'est plus valide. EF prend désormais en charge les types Geography.
Marcelo Mason
1
Nerveless EF prend en charge les types spatiaux, il utilise un ensemble de types différents pour les services de données WCF, il n'y a donc pas de compatibilité
abatishchev
1
hibernate 5 spatial ne fonctionne toujours pas par exemple :(
Eugene
1
Fair Warning applique toujours Entity Framework Core 2.0 github.com/aspnet/EntityFrameworkCore/issues/1100
ono2012
29

Je ne connais pas la réponse pour SQL Server mais ...

Dans MySQL, enregistrez-le sousFLOAT( 10, 6 )

Ceci est la recommandation officielle de la documentation des développeurs Google .

CREATE TABLE `coords` (
  `lat` FLOAT( 10, 6 ) NOT NULL ,
  `lng` FLOAT( 10, 6 ) NOT NULL ,
) ENGINE = MYISAM ;
Powtac
la source
19
La question indique clairement SQL Server, pas MySQL. Et vous ne voudriez certainement pas d'une table avec seulement la latitude et la longitude comme ça.
araqnid
2
D'accord - mauvaise réponse. Utilisez le nouveau type spatial GEOGRAPHY.
Pure.Krome
2
Le lien a également été déplacé vers code.google.com/apis/maps/articles/phpsqlajax.html
Ralph Lavelle
14
Je n'utiliserais pas float à cause de problèmes de précision. Utilisez décimal (9,6).
kaptan
Il existe des cas réels où les performances latet les lngperformances sont supérieures georgraphy, même avec des index à haute densité dans SQL 2014. Par exemple: find all point is withing a rectangle. Seulement je ne suis pas sûr, je vois que Google Maps utilise maintenant 7 au lieu de 6 chiffres?
Nenad
22

La façon dont je le fais: je stocke la latitude et la longitude , puis j'ai une troisième colonne qui est un type de géographie dérivée automatique des deux premières colonnes. Le tableau ressemble à ceci:

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

Cela vous donne la flexibilité des requêtes spatiales sur la colonne geoPoint et vous pouvez également récupérer les valeurs de latitude et de longitude lorsque vous en avez besoin pour l'affichage ou l'extraction à des fins csv.

jaxxbo
la source
super pour ce que je cherchais, avez-vous quelque chose pour les pistes / lignes
aggie
Une autre approche qui pourrait également fonctionner, en fonction de votre scénario, consiste à stocker le long et le lat, puis à créer dynamiquement l'objet géographique à la volée au moment de l'exécution.
Zapnologica
1
Bonne idée, mais sachez que vous ne pouvez pas créer d'index spatiaux sur des colonnes calculées si telle est l'intention de quelqu'un.
hvaughan3
1
@ hvaughan3 Je pense que vous pouvez si vous en faites une colonne calculée persistante .
NickG
2
Merci et +1, votre réponse m'a aidé. Mais je pense qu'il serait préférable d'utiliser Pointau lieu de STGeomFromText. Par exemple: [geography]::Point([Latitude], [Longitude], 4326).
default.kramer
21

Je déteste être à l'opposé de ceux qui ont dit "voici un nouveau type, utilisons-le". Les nouveaux types spatiaux de SQL Server 2008 ont certains avantages, à savoir l'efficacité, mais vous ne pouvez pas dire aveuglément toujours utiliser ce type. Cela dépend vraiment de certains problèmes de vue d'ensemble.

À titre d'exemple, l'intégration. Ce type a un type équivilent dans .Net - mais qu'en est-il de l'interopérabilité? Qu'en est-il de la prise en charge ou de l'extension des anciennes versions de .Net? Qu'en est-il d'exposer ce type à travers la couche de service à d'autres plates-formes? Qu'en est-il de la normalisation des données - peut-être êtes-vous intéressé par lat ou long en tant qu'éléments d'information autonomes. Peut-être avez-vous déjà écrit une logique métier complexe pour gérer long / lat.

Je ne dis pas que vous ne devriez pas utiliser le type spatial - dans de nombreux cas, vous devriez le faire. Je dis simplement que vous devriez poser des questions plus critiques avant de vous engager dans cette voie. Pour que je réponde plus précisément à votre question, j'aurais besoin d'en savoir plus sur votre situation spécifique.

Le stockage de long / lat séparément ou dans un type spatial sont deux solutions viables, et l'une peut être préférable à l'autre en fonction de vos propres circonstances.

R. Lawson
la source
Le SIG et le traitement des données spatiales ont une longue histoire et des représentations textuelles binaires standard depuis au moins les années 2000. Vous vous retrouverez avec tous les problèmes que vous avez mentionnés si vous n'utilisez pas les types spatiaux et les représentations standard
Panagiotis Kanavos
15

Ce que vous voulez faire est de stocker la latitude et la longitude en tant que nouveau type spatial SQL2008 -> GEOGRAPHIE.

Voici une capture d'écran d'une table, que j'ai.

texte alternatif http://img20.imageshack.us/img20/6839/zipcodetable.png

Dans ce tableau, nous avons deux champs qui stockent des données géographiques.

  • Limite: c'est le polygone qui est la limite du code postal
  • CentrePoint: c'est le point Latitude / Longitude qui représente le point médian visuel de ce polygone.

La principale raison pour laquelle vous voulez l'enregistrer dans la base de données en tant que type GEOGRAPHY est que vous pouvez ensuite tirer parti de toutes les méthodes SPATIALES -> par exemple. Point en poly, distance entre deux points, etc.

BTW, nous utilisons également l'API Google Maps pour récupérer les données lat / long et les stocker dans notre base de données Sql 2008 - donc cette méthode fonctionne.

Pure.Krome
la source
1
Et si vous n'êtes pas encore sur 2008, ou si vous utilisez SQLCE? Ce dernier ne prend pas en charge le type GEOGRAPHY ...
fretje
3
Si SqlCE ou <2008 prend en charge binary, il est possible de stocker les résultats dans varbinary, puis d'utiliser la DLL de la bibliothèque d'outils spatiaux pour effectuer des calculs spatiaux par rapport à cette représentation de données binaires dans votre code .NET. Ce n'est pas la meilleure solution, mais toujours une solution possible à certains problèmes. (nuget pour sql spatial .. pour récupérer cette dll).
Pure.Krome
2
Le lien de l'image est rompu
Bryan Denny
urgh :( merci pour rien imageshack. Je n'ai pas utilisé IS depuis des années :( imgur.com tout le chemin!
Pure.Krome
1
-1, cette réponse est incomplète sans l'image. Veuillez envisager de la remplacer par une nouvelle image ou une description de tableau textuel, ou de supprimer cette réponse.
Ilmari Karonen
11

SQL Server prend en charge les informations spatiales. Vous pouvez en savoir plus sur http://www.microsoft.com/sqlserver/2008/en/us/spatial-data.aspx .

Alternativement, vous pouvez stocker les informations sous forme de deux champs de base, généralement un flottant est le type de données standard signalé par la plupart des appareils et est suffisamment précis pour un pouce ou deux - plus que suffisant pour Google Maps.

Rosstifié
la source
2

REMARQUE : il s'agit d'une réponse récente basée sur des mises à jour récentes du serveur SQL et de la pile .NET

La latitude et la longitude de google Maps doivent être stockées en tant que données Point (note P majuscule) dans le serveur SQL sous le type de données géographie.

En supposant que vos données actuelles sont stockées dans une table en Sampletant que varchar sous les colonnes latet que la lonrequête ci-dessous vous aidera à vous convertir en géographie

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

PS: la prochaine fois que vous effectuez une sélection sur cette table avec des données géographiques, en dehors de l'onglet Résultats et Messages, vous obtiendrez également l'onglet Résultats spatiaux comme ci-dessous pour la visualisation

Onglet des résultats géographiques SSMS

DhruvJoshi
la source
0

Si vous utilisez Entity Framework 5 <, vous pouvez utiliser DbGeography. Exemple de 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

Quelque chose avec lequel j'ai eu du mal, puis j'ai commencé à utiliser, DbGeographyc'était le coordinateSystemId. Voir la réponse ci-dessous pour une excellente explication et la source du code ci-dessous.

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
la source
-4

Si vous voulez simplement le remplacer par une URL, je suppose qu'un champ ferait l'affaire - vous pouvez donc former une URL comme

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

mais comme il s'agit de deux données, je les stocke dans des champs séparés

Kristen
la source
C'est mon cas. J'ai besoin de stocker les coordonnées dans un seul champ et séparées par une virgule. Je pense que l'on pourrait utiliser un TEXTE comme type de champ. Qu'est-ce que tu penses?
Amr
-10

Stockez les deux en tant que flottant et utilisez des mots clés uniques dessus.

create table coordinates(
coord_uid counter primary key,
latitude float,
longitude float,
constraint la_long unique(latitude, longitude)
);
Graviton
la source
Pour s'assurer qu'il n'y a qu'un seul ensemble unique de paires de latitude et de longitude. Vous ne voulez pas stocker les coordonnées {0,0} deux fois dans votre table, n'est-ce pas?
Graviton
1
Vous ne voulez probablement pas du tout avoir une table de coordonnées séparée comme celle-ci, en particulier avec la contrainte d'unicité, c'est un cauchemar de maintenance qui gère le cas où deux emplacements font référence au même point, sans parler du nettoyage des lignes non référencées.
araqnid
2
> Vous ne voulez probablement pas du tout avoir une table de coordonnées séparée comme celle-ci - Pas du tout? Jamais? Comment stockeriez-vous cela dans 1 champ? Qu'en est-il des millions de personnes n'utilisant PAS le type spatial SQL 2008?
Sally
2
Avoir une telle contrainte est une mauvaise décision. Supposons que Bob habite House Aet déménage dans House Bla maison où vivait Alice. Bientôt, Bob ne pourra pas enregistrer son adresse (emplacement), car Alice n'a pas encore mis à jour la sienne - ou ne le fera jamais.
jweyrich
@Sally - ce n'est pas ce qu'il a dit. Lisez son commentaire. Il a dit qu'il ne devrait y avoir aucune raison de stocker une paire de valeurs dans une table séparée . Il suffit de mettre le lat / long sur la table d'origine et d'économiser les frais généraux d'une deuxième table et de tous les JOINS.
NickG le