Qual é a melhor maneira de armazenar coordenadas (longitude / latitude, do Google Maps) no SQL Server?


103

Estou projetando uma tabela no SQL Server 2008 que armazenará uma lista de usuários e uma coordenada do Google Maps (longitude e latitude).

Vou precisar de dois campos ou posso fazer com 1?

Qual é o melhor (ou mais comum) tipo de dados a ser usado para armazenar esse tipo de dados?

Respostas:



63

Aviso justo! Antes de seguir o conselho para usar o tipo GEOGRAPHY, certifique-se de que não está planejando usar o Linq ou Entity Framework para acessar os dados porque não é compatível (desde novembro de 2010) e você ficará triste!

Atualização em julho de 2017

Para aqueles que estão lendo esta resposta agora, ela é obsoleta no que se refere à pilha de tecnologia retroativa. Veja comentários para mais detalhes.


1
Como a resposta original foi postada, encontrei este artigo jasonfollas.com/blog/archive/2010/02/14/… discutindo uma possível solução alternativa.
Norman H

56
Aviso não é mais válido. EF agora oferece suporte a tipos de geografia.
Marcelo Mason

1
Nerveless EF oferece suporte a tipos espaciais, ele usa tipos diferentes definidos para serviços de dados WCF, portanto, não são compatíveis
abatishchev

1
o hibernate 5 espacial ainda não, por exemplo :(
Eugene

1
Fair Warning ainda se aplica ao Entity Framework Core 2.0 github.com/aspnet/EntityFrameworkCore/issues/1100
ono2012

29

Não sei a resposta para o SQL Server, mas ...

No MySQL, salve-o comoFLOAT( 10, 6 )

Esta é a recomendação oficial da documentação do desenvolvedor do Google .

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

19
A pergunta afirma claramente o SQL Server, não o MySQL. E você certamente não iria querer uma mesa apenas com latitude e longitude sozinhas.
araqnid

2
Concordo - má resposta. Use o novo tipo espacial GEOGRAPHY.
Pure.Krome de


14
Eu não usaria float por causa de problemas de precisão. Use decimal (9,6).
kaptan

Há casos reais em que onde late lngsuperam georgraphy, mesmo com índices de alta densidade no SQL 2014. Por exemplo: localizar todos os pontos está dentro de um retângulo. Só não tenho certeza, vejo que o Google Maps agora usa 7 em vez de 6 dígitos.
Nenad

22

A maneira como eu faço isso: eu armazeno a latitude e a longitude e, em seguida, tenho uma terceira coluna que é um tipo de geografia derivado automaticamente das primeiras duas colunas. A tabela é parecida com esta:

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

Isso dá a você a flexibilidade de consultas espaciais na coluna geoPoint e você também pode recuperar os valores de latitude e longitude conforme necessário para exibição ou extração para fins de csv.


ótimo para o que eu estava procurando, você tem algo para faixas / linhas
aggie

Outra abordagem que também pode funcionar, dependendo do seu cenário, é armazenar o longo e o lat e, em seguida, apenas criar dinamicamente o objeto geográfico em tempo de execução.
Zapnologica

1
Ótima ideia, mas esteja ciente de que você não pode criar índices espaciais em colunas computadas se essa for a intenção de alguém.
hvaughan3 01 de

1
@ hvaughan3 Eu acho que você pode se você torná-la uma coluna computada persistente .
NickG

2
Obrigado e +1, sua resposta me ajudou. Mas acho que seria melhor usar em Pointvez de STGeomFromText. Por exemplo: [geography]::Point([Latitude], [Longitude], 4326).
default.kramer

21

Eu odeio ser contrária àqueles que dizem "aqui está um novo tipo, vamos usar". Os novos tipos espaciais do SQL Server 2008 têm alguns prós - a saber, eficiência, mas você não pode dizer cegamente sempre use esse tipo. Realmente depende de alguns problemas gerais.

Como exemplo, integração. Este tipo tem um tipo equivalente em .Net - mas e a interoperabilidade? Que tal oferecer suporte ou extensão de versões anteriores do .Net? Que tal expor esse tipo em toda a camada de serviço para outras plataformas? E quanto à normalização de dados - talvez você esteja interessado em informações de longa ou longa duração. Talvez você já tenha escrito uma lógica de negócios complexa para lidar com long / lat.

Não estou dizendo que você não deve usar o tipo espacial - em muitos casos, deve. Só estou dizendo que você deve fazer algumas perguntas mais críticas antes de seguir esse caminho. Para que eu responda à sua pergunta com mais precisão, preciso saber mais sobre sua situação específica.

Armazenar long / lat separadamente ou em um tipo espacial são soluções viáveis, e uma pode ser preferível à outra dependendo de suas próprias circunstâncias.


O GIS e o processamento de dados espaciais têm uma longa história e representações textuais binárias padrão, pelo menos desde os anos 2000. Você acabará com todos os problemas que mencionou se não usar os tipos espaciais e as representações padrão
Panagiotis Kanavos

15

O que você deseja fazer é armazenar a Latitude e Longitude como o novo tipo Espacial SQL2008 -> GEOGRAFIA.

Aqui está uma captura de tela de uma mesa, que eu tenho.

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

Nesta tabela, temos dois campos que armazenam dados geográficos.

  • Limite: este é o polígono que é o limite do CEP
  • CentrePoint: este é o ponto de Latitude / Longitude que representa o ponto médio visual deste polígono.

O principal motivo pelo qual você deseja salvá-lo no banco de dados como um tipo GEOGRAFIA é para que você possa aproveitar todos os métodos ESPACIAIS dele -> por exemplo. Ponto em Poly, Distância entre dois pontos, etc.

A propósito, também usamos a API do Google Maps para recuperar dados lat / long e armazená-los em nosso banco de dados Sql 2008 - portanto, esse método funciona.


1
E se você ainda não estiver em 2008 ou usar o SQLCE? Este último não suporta o tipo GEOGRAFIA ...
fretje

3
Se SqlCE ou <2008 oferecer suporte a binários, é possível armazenar os resultados em varbinary e, em seguida, usar a DLL da biblioteca de ferramentas espaciais para fazer cálculos espaciais em relação a esta representação de dados binários em seu código .NET. Não é a melhor solução, mas ainda é uma solução possível para alguns problemas. (nuget para sql espacial .. para pegar essa dll).
Pure.Krome

2
O link da imagem está quebrado
Bryan Denny

urgh :( obrigado por nada imageshack. Há anos não uso o IS :( ​​imgur.com até o fim!
Pure.Krome de

1
-1, esta resposta está incompleta sem a imagem. Considere substituí-la por uma nova imagem ou uma descrição textual de tabela ou excluir esta resposta.
Ilmari Karonen

11

O SQL Server oferece suporte para informações relacionadas ao espaço. Você pode ver mais em http://www.microsoft.com/sqlserver/2008/en/us/spatial-data.aspx .

Como alternativa, você pode armazenar as informações como dois campos básicos, geralmente um float é o tipo de dados padrão relatado pela maioria dos dispositivos e é preciso o suficiente para uma polegada ou duas - mais do que adequado para o Google Maps.


2

OBSERVAÇÃO : Esta é uma resposta recente com base no servidor SQL recente, atualizações de pilha do .NET

latitude e longitude do Google Maps devem ser armazenadas como dados de ponto (observe P maiúsculo) no servidor SQL sob o tipo de dados geográficos.

Assumindo que seus dados atuais estão armazenados em uma tabela Samplecomo varchar em colunas late lon, a consulta abaixo irá ajudá-lo a converter para geografia

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

PS: Da próxima vez que você fizer uma seleção nesta tabela com dados geográficos, além da guia Resultados e Mensagens, você também obterá a guia Resultados espaciais como abaixo para visualização

Guia de resultados geográficos de SSMS


0

Se você estiver usando o Entity Framework 5 <, você pode usar DbGeography. Exemplo do 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 contra o qual eu lutava quando comecei a usar DbGeographyera o coordinateSystemId. Veja a resposta abaixo para uma excelente explicação e fonte para o código abaixo.

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 você for apenas substituí-lo por um URL, suponho que um campo serviria - para que você possa formar um URL como

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

mas como são dois dados, eu os armazenaria em campos separados


Este é o meu caso. Preciso armazenar as coordenadas em apenas um campo e separadas por uma vírgula. Acho que se poderia usar um TEXTO como um tipo de campo. O que você acha?
Amr

-10

Armazene ambos como flutuante e use palavras-chave exclusivas neles.i.em

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

Para ter certeza de que há apenas 1 conjunto único de par de latitude e longitude. Você não quer armazenar coordenadas {0,0} duas vezes na sua mesa, não é?
Graviton

1
Você provavelmente não quer ter uma tabela de coordenadas separada como esta, especialmente com a restrição de exclusividade, é um pesadelo de manutenção lidar com o caso de dois locais se referirem ao mesmo ponto, sem mencionar a limpeza de linhas não referenciadas.
araqnid de

2
> Você provavelmente não quer ter uma tabela de coordenadas separada como esta - De jeito nenhum? Nunca? Como você armazenaria isso em 1 campo? E quanto aos milhões de pessoas que NÃO usam o tipo espacial do SQL 2008?
Sally de

2
Ter tal restrição é uma má decisão. Suponha que Bob more House Ae se mudará para House Ba casa onde Alice morava. Em breve Bob não poderá mais salvar seu endereço (local), porque Alice ainda não atualizou o dela - ou nunca o fará.
jweyrich

@Sally - não foi isso que ele disse. Leia seu comentário. Ele disse que não deveria haver razão para armazenar um par de valores em uma tabela separada . Apenas coloque a latitude / longitude na tabela original e salve a sobrecarga de uma segunda tabela e todos os JOINS.
NickG
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.