Как лучше всего хранить координаты (долгота / широта из карт Google) в SQL Server?

103

Я разрабатываю таблицу в SQL Server 2008, в которой будет храниться список пользователей и координаты Google Maps (долгота и широта).

Нужны ли мне два поля или можно с одним?

Какой тип данных лучше (или чаще всего) использовать для хранения такого рода данных?

Джонатан
источник

Ответы:

54

Взгляните на новые типы пространственных данных, которые были представлены в SQL Server 2008. Они предназначены для такого рода задач и делают индексацию и запросы намного проще и эффективнее.

Больше информации:

Крейг Бовис
источник
63

Честное предупреждение! Прежде чем следовать совету по использованию типа GEOGRAPHY, убедитесь, что вы не планируете использовать Linq или Entity Framework для доступа к данным, потому что он не поддерживается (по состоянию на ноябрь 2010 г.), и вам будет грустно!

Обновление июль 2017 г.

Для тех, кто читает этот ответ сейчас, он устарел, поскольку относится к устаревшему стеку технологий. См. Комментарии для более подробной информации.

dan90266
источник
1
Поскольку исходный ответ был опубликован, я нашел эту статью jasonfollas.com/blog/archive/2010/02/14/…, в которой обсуждается возможное решение.
Norman H
56
Предупреждение больше не действует. EF теперь поддерживает типы Geography.
Марсело Мейсон
1
Nerveless EF поддерживает пространственные типы, он использует другой тип, установленный для служб данных WCF, поэтому они несовместимы
абатищев
1
hibernate 5 пространственный еще не например :(
Евгений
1
Справедливое предупреждение по-прежнему применяется Entity Framework Core 2.0 github.com/aspnet/EntityFrameworkCore/issues/1100
ono2012,
29

Я не знаю ответа для SQL Server, но ...

В MySQL сохраните его какFLOAT( 10, 6 )

Это официальная рекомендация из документации для разработчиков Google .

CREATE TABLE `coords` (
  `lat` FLOAT( 10, 6 ) NOT NULL ,
  `lng` FLOAT( 10, 6 ) NOT NULL ,
) ENGINE = MYISAM ;
Powtac
источник
19
Вопрос четко указывает на SQL Server, а не на MySQL. И вам определенно не нужен стол, в котором есть только широта и долгота.
araqnid
2
Согласен - плохой ответ. Используйте новый пространственный тип GEOGRAPHY.
Pure.Krome
2
Ссылка тоже переместилась на code.google.com/apis/maps/articles/phpsqlajax.html
Ralph Lavelle,
14
Я бы не стал использовать float из-за проблем с точностью. Используйте десятичную дробь (9,6).
kaptan
Есть реальные случаи, когда где latи lngпревосходят по производительности georgraphyдаже с индексами высокой плотности в SQL 2014. Например: найти все точки внутри прямоугольника. Только я не уверен, я вижу, что в Google Maps теперь используется 7 вместо 6 цифр?
Nenad
22

Как я это делаю: я сохраняю широту и долготу, а затем у меня есть третий столбец, который является автоматически производным типом географии первых двух столбцов. Таблица выглядит так:

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

Это дает вам гибкость пространственных запросов в столбце geoPoint, и вы также можете извлекать значения широты и долготы по мере необходимости для отображения или извлечения для целей csv.

jaxxbo
источник
отлично
подходит
Другой подход, который также может работать, в зависимости от вашего сценария, - это сохранение долгого и широтного числа, а затем просто динамическое создание объекта географии на лету во время выполнения.
Zapnologica
1
Отличная идея, но имейте в виду, что вы не можете создавать пространственные индексы для вычисляемых столбцов, если это кто-то намерен.
hvaughan3 01
1
@ hvaughan3 Я думаю, вы сможете, если сделаете его постоянным вычисляемым столбцом.
NickG
2
Спасибо и +1, ваш ответ мне помог. Но я думаю, что лучше было бы использовать Pointвместо STGeomFromText. Например: [geography]::Point([Latitude], [Longitude], 4326).
default.kramer
21

Ненавижу противоречить тем, кто сказал: «Вот новый тип, давайте воспользуемся им». Новые пространственные типы SQL Server 2008 имеют некоторые преимущества, а именно эффективность, однако вы не можете слепо сказать, что всегда используйте этот тип. Это действительно зависит от более серьезных проблем с картиной.

Например, интеграция. Этот тип имеет эквивалентный тип в .Net - но как насчет взаимодействия? А как насчет поддержки или расширения старых версий .Net? Как насчет того, чтобы раскрыть этот тип на уровне сервиса для других платформ? Что насчет нормализации данных - может быть, вас интересуют широта или долгота как отдельные части информации. Возможно, вы уже написали сложную бизнес-логику для обработки долгого и долгого времени.

Я не говорю, что вам не следует использовать пространственный тип - во многих случаях вам нужно. Я просто говорю, что вам следует задать еще несколько критических вопросов, прежде чем идти по этому пути. Чтобы я мог наиболее точно ответить на ваш вопрос, мне нужно было больше узнать о вашей конкретной ситуации.

Хранение long / lat отдельно или в пространственном типе - оба жизнеспособных решения, и одно может быть предпочтительнее другого в зависимости от ваших собственных обстоятельств.

Р. Лоусон
источник
ГИС и обработка пространственных данных имеют долгую историю и стандартные текстовые, двоичные представления, по крайней мере, с 2000-х годов. Вы будете в конечном итоге со всеми проблемы , которые вы упомянули , если вы не использовать пространственные типы и стандартные представления
Панайотис Kanavos
15

Что вы хотите сделать, так это сохранить широту и долготу как новый пространственный тип SQL2008 -> GEOGRAPHY.

Вот скриншот стола, который у меня есть.

альтернативный текст http://img20.imageshack.us/img20/6839/zipcodetable.png

В этой таблице у нас есть два поля, в которых хранятся географические данные.

  • Граница: это многоугольник, который является границей почтового индекса.
  • CentrePoint: это точка широты / долготы, которая представляет визуальную среднюю точку этого многоугольника.

Основная причина, по которой вы хотите сохранить его в базе данных как тип GEOGRAPHY, заключается в том, чтобы вы могли затем использовать все методы SPATIAL из него -> например. Точка в поли, расстояние между двумя точками и т. Д.

Кстати, мы также используем Google Maps API для получения данных о широте и долготе и сохранения их в нашей базе данных Sql 2008, поэтому этот метод действительно работает.

Pure.Krome
источник
1
А что, если у вас еще нет 2008 года, или что, если вы используете SQLCE? Последний не поддерживает тип ГЕОГРАФИЯ ...
fretje
3
Если SqlCE или <2008 поддерживает двоичный код, можно сохранить результаты в виде varbinary, а затем использовать dll библиотеки Spatial tools для выполнения пространственных вычислений относительно этого двоичного представления данных в вашем .NET-коде. Не лучшее решение, но все же возможное решение некоторых проблем. (nuget для sql пространственного .. чтобы захватить эту dll).
Pure.Krome
2
Ссылка на изображение не работает
Брайан Денни
urgh :( спасибо, что ничего не сделал, imageshack. Я не использовал IS уже много лет :( imgur.com полностью!
Pure.Krome
1
-1, этот ответ неполный без изображения. Пожалуйста, подумайте о том, чтобы заменить его новым изображением или описанием текстовой таблицы либо удалить этот ответ.
Ilmari Karonen
11

SQL Server поддерживает пространственную информацию. Вы можете увидеть больше на http://www.microsoft.com/sqlserver/2008/en/us/spatial-data.aspx .

В качестве альтернативы вы можете сохранить информацию в виде двух основных полей, обычно float является стандартным типом данных, сообщаемым большинством устройств и достаточно точным в пределах одного-двух дюймов - более чем достаточно для Google Maps.

Росстифицированный
источник
2

ПРИМЕЧАНИЕ . Это недавний ответ, основанный на последних обновлениях стека SQL Server и .NET.

широта и долгота из карт Google должны храниться как данные Point (обратите внимание на заглавную букву P) на сервере SQL в соответствии с типом данных geography.

Предполагая, что ваши текущие данные хранятся в таблице Sampleкак varchar под столбцами, latи lonзапрос ниже поможет вам преобразовать в географию

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

PS: В следующий раз, когда вы сделаете выбор в этой таблице с географическими данными, помимо вкладки «Результаты» и «Сообщения», вы также получите вкладку «Пространственные результаты», как показано ниже, для визуализации.

Вкладка результатов гео SSMS

ДхрувДжоши
источник
0

Если вы используете Entity Framework 5 <, вы можете использовать DbGeography . Пример из 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

То, с чем я боролся, когда я начал использовать, DbGeographyбыло coordinateSystemId. См. Ответ ниже, где вы найдете прекрасное объяснение и исходный код приведенного ниже кода.

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
источник
-4

Если вы просто собираетесь подставить его в URL-адрес, я полагаю, подойдет одно поле, поэтому вы можете сформировать URL-адрес, например

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

но поскольку это два фрагмента данных, я бы сохранил их в отдельных полях

Кристен
источник
Это мой случай. Мне нужно сохранить координаты только в одном поле и разделить их запятыми. Я думаю, что можно использовать ТЕКСТ как тип поля. Что вы думаете?
Amr
-10

Сохраните оба объекта как float и используйте в них уникальные ключевые слова. I.em

create table coordinates(
coord_uid counter primary key,
latitude float,
longitude float,
constraint la_long unique(latitude, longitude)
);
Гравитон
источник
Чтобы убедиться, что существует только 1 уникальный набор пары широты и долготы. Вы же не хотите дважды сохранять координату {0,0} в своей таблице, не так ли?
Graviton
1
Вероятно, вы вообще не захотите иметь отдельную таблицу координат, как эта, особенно с ограничением уникальности, это кошмар обслуживания, когда два местоположения относятся к одной и той же точке, не говоря уже об очистке строк, на которые нет ссылок.
araqnid
2
> Вы, наверное, вообще не хотите иметь такую ​​отдельную таблицу координат - Вовсе нет? Никогда? Как бы вы сохранили это в 1 поле? А как насчет миллионов людей, НЕ использующих пространственный тип SQL 2008?
Салли
2
Такое ограничение - плохое решение. Предположим, Боб живет в доме, где раньше жила Алиса House A, и переедет в него House B. Вскоре Боб не сможет сохранить свой адрес (местоположение), потому что Алиса еще не обновила свой адрес - или никогда не обновит.
jweyrich
@ Салли, он не это сказал. Прочтите его комментарий. Он сказал, что не должно быть причин хранить пару значений в отдельной таблице . Просто поместите lat / long в исходную таблицу и сохраните накладные расходы на вторую таблицу и все JOINS.
NickG