¿Cuál es la mejor manera de almacenar coordenadas (longitud / latitud, de Google Maps) en SQL Server?


103

Estoy diseñando una tabla en SQL Server 2008 que almacenará una lista de usuarios y una coordenada de Google Maps (longitud y latitud).

¿Necesitaré dos campos o se puede hacer con 1?

¿Cuál es el mejor (o el más común) tipo de datos a utilizar para almacenar este tipo de datos?

Respuestas:



63

¡Advertencia justa! Antes de seguir el consejo de usar el tipo GEOGRAPHY, asegúrese de que no planea usar Linq o Entity Framework para acceder a los datos porque no es compatible (a partir de noviembre de 2010) y se entristecerá.

Actualización de julio de 2017

Para aquellos que lean esta respuesta ahora, es obsoleta, ya que se refiere a la pila de tecnología retroactiva. Consulte los comentarios para obtener más detalles.


1
Desde que se publicó la respuesta original, encontré este artículo jasonfollas.com/blog/archive/2010/02/14/… discutiendo una posible solución.
Norman H

56
La advertencia ya no es válida. EF ahora admite tipos de geografía.
Marcelo Mason

1
Nerveless EF admite tipos espaciales, utiliza un conjunto de tipos diferente para WCF Data Services, por lo que no son compatibles
abatishchev

1
hibernate 5 espacial todavía no, por ejemplo :(
Eugene

1
La advertencia justa todavía se aplica a Entity Framework Core 2.0 github.com/aspnet/EntityFrameworkCore/issues/1100
ono2012

29

No sé la respuesta para SQL Server pero ...

En MySQL guárdelo comoFLOAT( 10, 6 )

Esta es la recomendación oficial de la documentación para desarrolladores de Google .

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

19
La pregunta establece claramente SQL Server, no MySQL. Y ciertamente no querrás una mesa con solo latitud y longitud por sí solas como esa.
araqnid

2
De acuerdo, mala respuesta. Utilice el nuevo tipo espacial GEOGRAPHY.
Pure.Krome


14
No usaría flotador debido a problemas de precisión. Utilice decimal (9,6).
kaptan

Hay casos reales donde laty lngsuperan georgraphy, incluso con índices de alta densidad en SQL 2014. Por ejemplo: encontrar todos los puntos está dentro de un rectángulo. Solo que no estoy seguro, veo que Google Maps ahora usa 7 en lugar de 6 dígitos.
Nenad

22

La forma en que lo hago: almaceno la latitud y la longitud y luego tengo una tercera columna que es un tipo de geografía derivada automáticamente de las primeras dos columnas. La tabla se ve así:

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

Esto le brinda la flexibilidad de las consultas espaciales en la columna geoPoint y también puede recuperar los valores de latitud y longitud cuando los necesite para mostrarlos o extraerlos con fines de csv.


genial para lo que estaba buscando, ¿tienes algo para pistas / líneas
aggie

Otro enfoque que también podría funcionar, dependiendo de su escenario, es almacenar el largo y el lat, y luego simplemente crear dinámicamente el objeto de geografía sobre la marcha en tiempo de ejecución.
Zapnologica

1
Gran idea, pero tenga en cuenta que no puede crear índices espaciales en columnas calculadas si esa es la intención de alguien.
hvaughan3

1
@ hvaughan3 Creo que puede hacerlo si lo convierte en una columna calculada persistente .
NickG

2
Gracias y +1, tu respuesta me ayudó. Pero creo que sería mejor usar en Pointlugar de STGeomFromText. Por ejemplo: [geography]::Point([Latitude], [Longitude], 4326).
default.kramer

21

Odio ser contrario a aquellos que dijeron "aquí hay un nuevo tipo, usémoslo". Los nuevos tipos espaciales de SQL Server 2008 tienen algunas ventajas: la eficiencia, sin embargo, no se puede decir ciegamente que siempre use ese tipo. Realmente depende de algunos problemas de imagen más amplios.

Como ejemplo, integración. Este tipo tiene un tipo equivalente en .Net, pero ¿qué pasa con la interoperabilidad? ¿Qué hay de admitir o ampliar versiones anteriores de .Net? ¿Qué hay de exponer este tipo a través de la capa de servicio a otras plataformas? ¿Qué pasa con la normalización de datos? Tal vez le interese la latitud o la longitud como piezas de información independientes. Quizás ya haya escrito una lógica empresarial compleja para manejar long / lat.

No estoy diciendo que no debas usar el tipo espacial, en muchos casos deberías hacerlo. Solo digo que debería hacer algunas preguntas más críticas antes de seguir ese camino. Para poder responder a su pregunta con mayor precisión, necesitaría saber más sobre su situación específica.

Almacenar long / lat por separado o en un tipo espacial son soluciones viables, y una puede ser preferible a la otra dependiendo de sus propias circunstancias.


Los SIG y el procesamiento de datos espaciales tienen una larga historia y representaciones binarias textuales estándar al menos desde la década de 2000. Terminará con todos los problemas que mencionó si no usa los tipos espaciales y las representaciones estándar
Panagiotis Kanavos

15

Lo que desea hacer es almacenar la latitud y la longitud como el nuevo tipo espacial SQL2008 -> GEOGRAFÍA.

Aquí hay una captura de pantalla de una mesa, que tengo.

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

En esta tabla, tenemos dos campos que almacenan datos geográficos.

  • Límite: este es el polígono que es el límite del código postal
  • CentrePoint: este es el punto de latitud / longitud que representa el punto medio visual de este polígono.

La razón principal por la que desea guardarlo en la base de datos como un tipo GEOGRAPHY es para que pueda aprovechar todos los métodos ESPACIALES de él -> ej. Punto en Poli, Distancia entre dos puntos, etc.

Por cierto, también usamos la API de Google Maps para recuperar datos lat / long y almacenarlos en nuestra base de datos Sql 2008, por lo que este método funciona.


1
¿Y si aún no está en 2008 o si usa SQLCE? Este último no es compatible con el tipo GEOGRAPHY ...
traste

3
Si SqlCE o <2008 admite binarios, es posible almacenar los resultados son varbinary y luego usar la biblioteca de herramientas espaciales dll para hacer cálculos espaciales contra esta representación de datos binarios en su código .NET. No es la mejor solución, pero sigue siendo una posible solución a algunos problemas. (nuget para sql espacial .. para tomar ese dll).
Pure.Krome

2
Enlace de imagen roto
Bryan Denny

urgh :( gracias por nada imageshack. No he usado IS durante años :( imgur.com hasta el final!
Pure.Krome

1
-1, esta respuesta está incompleta sin la imagen. Considere reemplazarlo con una nueva imagen o una descripción de tabla textual, o eliminar esta respuesta.
Ilmari Karonen

11

SQL Server tiene soporte para información relacionada con el espacio. Puede ver más en http://www.microsoft.com/sqlserver/2008/en/us/spatial-data.aspx .

Alternativamente, puede almacenar la información como dos campos básicos, por lo general, un flotante es el tipo de datos estándar informado por la mayoría de los dispositivos y es lo suficientemente preciso para una pulgada o dos, más que adecuado para Google Maps.


2

NOTA : Esta es una respuesta reciente basada en el servidor SQL reciente, actualizaciones de pila .NET

La latitud y la longitud de Google Maps deben almacenarse como datos de punto (nota P mayúscula) en el servidor SQL bajo el tipo de datos geográficos.

Suponiendo que sus datos actuales están almacenados en una tabla Samplecomo varchar debajo de las columnas laty lon, la consulta a continuación lo ayudará a convertir a geografía

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

PD: La próxima vez que haga una selección en esta tabla con datos geográficos, además de la pestaña Resultados y Mensajes, también obtendrá la pestaña Resultados espaciales como la siguiente para visualización

Pestaña de resultados geográficos de SSMS


0

Si está usando Entity Framework 5 <puede usar DbGeography. Ejemplo 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

Algo con lo que luché y luego comencé a usar DbGeographyfue el coordinateSystemId. Consulte la respuesta a continuación para obtener una excelente explicación y fuente del código a continuación.

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

Si solo va a sustituirlo en una URL, supongo que un campo sería suficiente, para que pueda formar una URL como

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

pero como son dos datos, los almacenaría en campos separados


Este es mi caso. Necesito almacenar las coordenadas en un solo campo y separadas por una coma. Creo que se podría usar un TEXTO como tipo de campo. ¿Qué piensas?
Amr

-10

Almacene ambos como flotantes y use palabras clave únicas en ellos.

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

Para asegurarse de que solo haya un conjunto único de par de latitud y longitud. No desea almacenar las coordenadas {0,0} dos veces en su tabla, ¿no es así?
Graviton

1
Probablemente no desee tener una tabla de coordenadas separada como esta en absoluto, especialmente con la restricción de unicidad, es una pesadilla de mantenimiento manejar el caso de que dos ubicaciones se refieran al mismo punto, sin mencionar la limpieza de filas sin referencia.
araqnid

2
> Probablemente no desee tener una tabla de coordenadas separada como esta en absoluto - ¿En absoluto? ¿Nunca? ¿Cómo almacenarías eso en 1 campo? ¿Qué pasa con los millones de personas que NO utilizan SQL 2008 Spatial type?
Sally

2
Tener tal restricción es una mala decisión. Suponga que Bob vive House Ay se mudará a House Bla casa donde solía vivir Alice. Pronto Bob no podrá guardar su dirección (ubicación), porque Alice no actualizó la suya todavía, o nunca lo hará.
jweyrich

@Sally, eso no es lo que dijo. Lea su comentario. Dijo que no debería haber ninguna razón para almacenar un par de valores en una tabla separada . Simplemente coloque la latitud / longitud en la tabla original y guarde la sobrecarga de una segunda tabla y todas las UNIONES.
NickG
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.