Який найкращий спосіб зберігати координати (довгота / широта від Карт Google) на SQL Server?


103

Я розробляю таблицю в SQL Server 2008, яка буде зберігати список користувачів та координати Карт Google (довгота та широта).

Чи знадобляться мені два поля чи це можна зробити з 1?

Який найкращий (або найпоширеніший) тип даних використовувати для зберігання такого роду даних?

Відповіді:


54

Погляньте на нові просторові типи даних, які були представлені в SQL Server 2008. Вони розроблені для такого роду завдань і роблять індексацію та запити набагато простішими та ефективнішими.

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


63

Справедливе попередження! Перш ніж приймати поради щодо використання типу GEOGRAPHY, переконайтесь, що ви не плануєте використовувати Linq або Entity Framework для доступу до даних, оскільки це не підтримується (станом на листопад 2010 року), і вам буде сумно!

Оновлення липня 2017 року

Для тих, хто зараз читає цю відповідь, вона застаріла, оскільки вона посилається на застарілий стек технологій. Дивіться коментарі для більш детальної інформації.


1
Оскільки оригінальна відповідь була опублікована, я знайшов цю статтю jasonfollas.com/blog/archive/2010/02/14/…, яка обговорювала можливе вирішення.
Норман Н

56
Попередження більше не діє. EF тепер підтримує типи географії.
Марсело Мейсон

1
Nerveless EF підтримує просторові типи, він використовує різні типи для WCF Data Services, тому вони не сумісні
абатищев

1
зимувати 5 просторових ще не є, наприклад :(
Євген

1
Справедливе попередження все ще застосовується Entity Framework Core 2.0 github.com/aspnet/EntityFrameworkCore/isissue/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 ;

19
У питанні чітко зазначено SQL Server, а не MySQL. І ви, звичайно, не хочете, щоб стіл з простою широтою і довготою був такий самий.
araqnid

2
Погоджена -бадкова відповідь. Використовуйте новий просторовий тип GEOGRAPHY.
Pure.Krome

2
Посилання також перейшло на code.google.com/apis/maps/articles/phpsqlajax.html
Ральф Лавель,

14
Я б не використовував float через проблеми з точністю. Використовуйте десятковий (9,6).
каптан

Існують фактичні випадки, коли latі lngперевершує georgraphyнавіть у індексах високої щільності в SQL 2014. Наприклад: знайти всю точку - це прямокутник. Тільки я не впевнений, я бачу, що в Google Maps зараз використовується 7 замість 6 цифр?
Ненад

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.


чудово для того, що я шукав, чи є у вас що-небудь для треків / ліній
aggie

Інший підхід, який також може працювати, залежно від вашого сценарію, - це зберігання тривалості та лат, а потім просто динамічно створюючи географічний об’єкт під час руху під час виконання.
Zapnologica

1
Чудова ідея, але пам’ятайте, що ви не можете створити просторові індекси на обчислених стовпцях, якщо це чийсь намір.
hvaughan3

1
@ hvaughan3 Я думаю, ви можете, якщо ви зробите це стійким обчисленим стовпцем.
NickG

2
Дякую і +1, ваша відповідь допомогла мені. Але я думаю, що краще було б використовувати Pointзамість цього STGeomFromText. Наприклад: [geography]::Point([Latitude], [Longitude], 4326).
default.kramer

21

Я ненавиджу бути противником тим, хто сказав "ось новий тип, давайте скористаємося цим". Нові просторові типи SQL Server 2008 мають певні плюси - а саме ефективність, однак не можна сліпо сказати, що завжди використовуйте цей тип. Це дійсно залежить від декількох проблем з більшою картиною.

Як приклад - інтеграція. Цей тип має еквівалентний тип у .Net - а як же інтероп? Що щодо підтримки чи розширення старих версій .Net? Що щодо експонування цього типу на рівні сервісу на інших платформах? Як щодо нормалізації даних - можливо, вас цікавлять лати або довгі, як окремі відомості. Можливо, ви вже написали складну ділову логіку, щоб обробляти довго / лат.

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

Зберігання довгих / лат окремо або в просторовому типі є життєздатними рішеннями, і одне може бути кращим перед іншим залежно від ваших власних обставин.


ГІС та обробка просторових даних мають довгу історію та стандартні текстові, бінарні уявлення, щонайменше, з 2000-х років. Ви з усіма згаданими вами проблемами закінчите, якщо не будете використовувати просторові типи та стандартні зображення
Panagiotis Kanavos

15

Що ви хочете зробити, це зберігати широту та довготу як новий просторовий тип SQL2008 -> ГЕОГРАФІЯ.

Ось знімок екрана таблиці, який у мене є.

alt text http://img20.imageshack.us/img20/6839/zipcodetable.png

У цій таблиці ми маємо два поля, в яких зберігаються дані географії.

  • Межа: це полігон, який є межею поштового індексу
  • CentrePoint: це точка широти / довготи, яка представляє візуальну середню точку цього багатокутника.

Основна причина, чому ви хочете зберегти його в базі даних як тип GEOGRAPHY, - це потім ви можете використовувати від неї всі СПЕЦІАЛЬНІ методи -> напр. Точка в Полі, Відстань між двома точками тощо.

До речі, ми також використовуємо API Карт Google для отримання даних lat / long і зберігаємо їх у нашому БД Sql 2008 - таким чином цей метод працює.


1
А що робити, якщо ви ще не в 2008 році, або що, якщо ви використовуєте SQLCE? Останній не підтримує тип GEOGRAPHY ...
fretje

3
Якщо SqlCE або <2008 підтримує бінарний файл, можна зберігати результати варбінарні, а потім використовувати dll бібліотеку просторових інструментів, щоб робити просторові обчислення проти цього представлення бінарних даних у вашому коді .NET. Не найкраще рішення, але все-таки можливе рішення деяких проблем. (nuget для sql просторового .. щоб схопити цей dll).
Pure.Krome

2
Посилання на зображення перервано
Брайан Денні

urgh :( дякую, що нічого не знімають. Я не використовував IS протягом багатьох років :( imgur.com увесь шлях!
Pure.Krome

1
-1, ця відповідь є неповною без зображення. Будь ласка, подумайте про те, щоб замінити його новим зображенням або описом текстової таблиці або видалити цю відповідь.
Ільмарі Каронен

11

SQL Server підтримує інформацію, пов'язану з простором. Більше ви можете побачити на веб- сайті http://www.microsoft.com/sqlserver/2008/en/us/spatial-data.aspx .

Ви також можете зберігати інформацію як два основних поля, зазвичай поплавок - це стандартний тип даних, про який повідомляє більшість пристроїв, і достатньо точний протягом дюйма або двох - більш ніж достатньо для Карт Google.


2

ПРИМІТКА . Це нещодавня відповідь, заснована на останніх серверах SQL, оновленнях стеків .NET

латитут і довгота з Google Maps повинні зберігатися у вигляді даних Point (замість капіталу P) на SQL-сервері під типом географічних даних.

Якщо припустити, що ваші поточні дані зберігаються в таблиці Sampleяк варчар під стовпцями, 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


-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} двічі у своєму столі, чи не так?
Гравітон

1
Ви, мабуть, зовсім не хочете мати окрему таблицю координат, особливо з обмеженням унікальності, це кошмар, який веде дотримання справи, що два місця посилаються на одну і ту ж точку, не кажучи вже про очищення нерозділених рядків.
аракнід

2
> Ви, мабуть, зовсім не хочете мати окрему таблицю координат, як це - Зовсім не? Ніколи? Як би ви зберегли це в 1 полі? Що з мільйонами людей, які НЕ використовують тип простору SQL 2008?
Саллі

2
Мати таке обмеження - це погане рішення. Припустимо, Боб живе House Aі переїде до House Bбудинку, де раніше жила Аліса. Незабаром Боб не зможе зберегти свою адресу (місцезнаходження), оскільки Аліса ще не оновлювала її - або ніколи не буде.
jweyrich

@ Саллі - це не те, що він сказав. Прочитайте його коментар. Він сказав, що не повинно бути причин зберігати пару значень в окремій таблиці . Просто покладіть lat / long на оригінальну таблицю і збережіть накладні витрати на другу таблицю та всі ПРИЄДНАННЯ.
NickG
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.