Cách tốt nhất để lưu trữ tọa độ (kinh độ / vĩ độ, từ Google Maps) trong SQL Server là gì?


103

Tôi đang thiết kế một bảng trong SQL Server 2008 sẽ lưu trữ danh sách người dùng và tọa độ Google Maps (kinh độ và vĩ độ).

Tôi sẽ cần hai trường hay có thể thực hiện bằng 1?

Loại dữ liệu tốt nhất (hoặc phổ biến nhất) để sử dụng để lưu trữ loại dữ liệu này là gì?

Câu trả lời:



63

Cảnh báo đúng! Trước khi thực hiện lời khuyên sử dụng loại GEOGRAPHY, hãy đảm bảo rằng bạn không định sử dụng Linq hoặc Entity Framework để truy cập dữ liệu vì nó không được hỗ trợ (kể từ tháng 11 năm 2010) và bạn sẽ rất buồn!

Cập nhật tháng 7 năm 2017

Đối với những người đọc câu trả lời này bây giờ, nó đã lỗi thời vì nó ám chỉ ngăn xếp công nghệ lạc hậu. Xem bình luận để biết thêm chi tiết.


1
Vì câu trả lời ban đầu đã được đăng, tôi thấy bài viết này jasonfollas.com/blog/archive/2010/02/14/… thảo luận về một giải pháp khả thi.
Norman H

56
Cảnh báo không còn hiệu lực. EF hiện hỗ trợ các loại Địa lý.
Marcelo Mason

1
Không có khí lực EF không hỗ trợ loại không gian, nó sử dụng bộ gõ khác nhau để WCF Data Services, do đó không có tương thích
abatishchev

1
không gian ngủ đông 5 không vẫn còn ví dụ :(
Eugene

1
Cảnh báo Công bằng vẫn áp dụng Entity Framework Core 2.0 github.com/aspnet/EntityFrameworkCore/issues/1100
ono2012

29

Tôi không biết câu trả lời cho SQL Server nhưng ...

Trong MySQL, hãy lưu nó dưới dạngFLOAT( 10, 6 )

Đây là khuyến nghị chính thức từ tài liệu dành cho nhà phát triển của Google .

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

19
Câu hỏi nêu rõ SQL Server, không phải MySQL. Và bạn chắc chắn sẽ không muốn một bảng chỉ có vĩ độ và kinh độ của riêng chúng như vậy.
araqnid

2
Đồng ý -bad câu trả lời. Sử dụng kiểu không gian GEOGRAPHY mới.
Pure.Krome

2
Liên kết cũng đã được chuyển tới code.google.com/apis/maps/articles/phpsqlajax.html
Ralph Lavelle,

14
Tôi sẽ không sử dụng float vì các vấn đề về độ chính xác. Sử dụng số thập phân (9,6).
kaptan

Có những trường hợp thực tế mà ở đó latvà hoạt động lngtốt hơn georgraphy, ngay cả với các chỉ số mật độ cao trong SQL 2014. Ví dụ: find all point is witering một hình chữ nhật. Chỉ có điều tôi không rõ, tôi thấy Google Maps bây giờ sử dụng chữ số 7 thay vì 6 chữ số?
Nenad

22

Cách tôi làm điều đó: Tôi lưu trữ vĩ độkinh độ và sau đó tôi có cột thứ ba là loại địa lý tự động có nguồn gốc từ hai cột đầu tiên. Bảng trông như thế này:

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

Điều này mang lại cho bạn sự linh hoạt của các truy vấn không gian trên cột geoPoint và bạn cũng có thể truy xuất các giá trị vĩ độ và kinh độ khi bạn cần để hiển thị hoặc trích xuất cho mục đích csv.


tuyệt vời cho những gì tôi đang tìm kiếm, bạn có bất cứ điều gì cho các bản nhạc / dòng không
aggie

Một cách tiếp cận khác cũng có thể hoạt động, tùy thuộc vào kịch bản của bạn, là lưu trữ độ dài và vĩ độ, sau đó chỉ cần tạo động đối tượng địa lý một cách nhanh chóng trong thời gian chạy.
Zapnologica

1
Ý tưởng tuyệt vời nhưng hãy lưu ý rằng bạn không thể tạo chỉ mục không gian trên các cột được tính toán nếu đó là ý định của ai đó.
hvaughan3

1
@ hvaughan3 Tôi nghĩ bạn có thể làm được nếu bạn đặt nó thành một cột được tính toán liên tục .
NickG

2
Cảm ơn và +1, câu trả lời của bạn đã giúp tôi. Nhưng tôi nghĩ sẽ tốt hơn nếu sử dụng Pointthay vì STGeomFromText. Ví dụ: [geography]::Point([Latitude], [Longitude], 4326).
default.kramer

21

Tôi ghét phải đối nghịch với những người đã nói "đây là một loại mới, chúng ta hãy sử dụng nó". Các kiểu không gian SQL Server 2008 mới có một số ưu điểm - cụ thể là hiệu quả, tuy nhiên bạn không thể nói một cách mù quáng là luôn sử dụng kiểu đó. Nó thực sự phụ thuộc vào một số vấn đề hình ảnh lớn hơn.

Như một ví dụ, tích hợp. Loại này có một loại tương đương trong .Net - nhưng còn interop thì sao? Điều gì về việc hỗ trợ hoặc mở rộng các phiên bản cũ hơn của .Net? Điều gì về việc hiển thị loại này trên lớp dịch vụ cho các nền tảng khác? Còn về việc chuẩn hóa dữ liệu - có thể bạn quan tâm đến các phần thông tin độc lập về vĩ độ hoặc lâu dài. Có lẽ bạn đã viết logic nghiệp vụ phức tạp để xử lý long / lat.

Tôi không nói rằng bạn không nên sử dụng kiểu không gian - trong nhiều trường hợp, bạn nên làm như vậy. Tôi chỉ nói rằng bạn nên hỏi một số câu hỏi quan trọng hơn trước khi đi xuống con đường đó. Để tôi trả lời câu hỏi của bạn chính xác nhất, tôi cần biết thêm về tình hình cụ thể của bạn.

Lưu trữ dài / vĩ độ riêng biệt hoặc trong một kiểu không gian đều là những giải pháp khả thi và cách này có thể phù hợp hơn với cách khác tùy thuộc vào hoàn cảnh của riêng bạn.


GIS và xử lý dữ liệu không gian đã có lịch sử lâu đời và các biểu diễn dạng văn bản, nhị phân tiêu chuẩn ít nhất từ ​​những năm 2000. Bạn sẽ kết thúc với tất cả các vấn đề bạn đề cập đến nếu bạn không sử dụng các loại không gian và cơ quan đại diện tiêu chuẩn
Panagiotis Kanavos

15

Những gì bạn muốn làm là lưu trữ Vĩ độ và Kinh độ ở dạng SQL2008 Spatial mới -> GEOGRAPHY.

Đây là ảnh chụp màn hình của một cái bàn mà tôi có.

văn bản thay thế http://img20.imageshack.us/img20/6839/zipcodetable.png

Trong bảng này, chúng ta có hai trường lưu trữ dữ liệu địa lý.

  • Ranh giới: đây là đa giác là ranh giới mã zip
  • CentrePoint: đây là điểm Vĩ độ / Kinh độ đại diện cho điểm giữa trực quan của đa giác này.

Lý do chính khiến bạn muốn lưu nó vào cơ sở dữ liệu dưới dạng kiểu GEOGRAPHY là vì vậy bạn có thể tận dụng tất cả các phương thức SPATIAL từ nó -> ví dụ: Điểm trong Poly, Khoảng cách giữa hai điểm, v.v.

BTW, chúng tôi cũng sử dụng API Maps của Google để truy xuất dữ liệu vĩ độ / dài và lưu trữ dữ liệu đó trong Sql 2008 DB của chúng tôi - vì vậy phương pháp này hoạt động.


1
Và nếu bạn chưa sử dụng phiên bản 2008, hoặc nếu bạn sử dụng SQLCE thì sao? Sau này không hỗ trợ kiểu ĐỊA LÝ ...
fretje

3
Nếu SqlCE hoặc <2008 hỗ trợ nhị phân, bạn có thể lưu trữ các kết quả là varbinary và sau đó sử dụng dll thư viện công cụ không gian để thực hiện các phép tính không gian dựa trên biểu diễn dữ liệu nhị phân này trong mã .NET của bạn. Không phải là giải pháp tốt nhất, nhưng vẫn là giải pháp khả thi cho một số vấn đề. (nuget cho sql spatial .. để lấy dll đó).
Pure.Krome

2
Liên kết hình ảnh được chia
Bryan Denny

urgh :( cảm ơn vì không có gì imagehack. Tôi đã không sử dụng IS trong nhiều năm :( imgur.com tất cả các cách!
Pure.Krome

1
-1, câu trả lời này không đầy đủ nếu không có hình ảnh. Vui lòng xem xét thay thế nó bằng một hình ảnh mới hoặc mô tả bảng văn bản, hoặc xóa câu trả lời này.
Ilmari Karonen

11

SQL Server có hỗ trợ thông tin liên quan đến không gian. Bạn có thể xem thêm tại http://www.microsoft.com/sqlserver/2008/en/us/spatial-data.aspx .

Ngoài ra, bạn có thể lưu trữ thông tin dưới dạng hai trường cơ bản, thường float là loại dữ liệu tiêu chuẩn được hầu hết các thiết bị báo cáo và đủ chính xác trong phạm vi một hoặc hai inch - quá đủ cho Google Maps.


2

LƯU Ý : Đây là câu trả lời gần đây dựa trên máy chủ SQL gần đây, các bản cập nhật ngăn xếp .NET

vĩ độ và kinh độ từ Google Maps nên được lưu trữ dưới dạng dữ liệu Điểm (ghi chú viết hoa P) trong máy chủ SQL theo kiểu dữ liệu địa lý.

Giả sử dữ liệu hiện tại của bạn được lưu trữ trong một bảng Sampledưới dạng varchar dưới các cột latlontruy vấn bên dưới sẽ giúp bạn chuyển đổi sang vị trí địa lý

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

Tái bút: Lần tới khi bạn chọn trên bảng này với dữ liệu địa lý, ngoài tab Kết quả và Tin nhắn, bạn cũng sẽ nhận được tab Kết quả không gian như bên dưới để hình dung

Tab kết quả địa lý SSMS


0

Nếu bạn đang sử dụng Entity Framework 5 <bạn có thể sử dụng DbGeography. Ví dụ từ 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

Một cái gì đó tôi đã đấu tranh với sau đó tôi bắt đầu sử dụng DbGeographycoordinateSystemId. Xem câu trả lời bên dưới để có lời giải thích tuyệt vời và nguồn cho mã bên dưới.

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

Nếu bạn chỉ định thay thế nó thành một URL, tôi cho rằng một trường sẽ làm được - vì vậy bạn có thể tạo một URL như

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

nhưng vì nó là hai phần dữ liệu nên tôi sẽ lưu trữ chúng trong các trường riêng biệt


Đây là trường hợp của tôi. Tôi chỉ cần lưu trữ các tọa độ trong một trường và được phân tách bằng dấu phẩy. Tôi nghĩ người ta có thể sử dụng TEXT làm loại trường. Bạn nghĩ sao?
Amr

-10

Lưu trữ cả hai dưới dạng float và sử dụng các từ khóa duy nhất trên chúng. I.em

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

Để đảm bảo rằng chỉ có 1 cặp kinh độ và vĩ độ duy nhất. Bạn không muốn lưu trữ tọa độ {0,0} hai lần trong bảng, phải không?
Graviton

1
Bạn có thể không muốn có một bảng tọa độ riêng biệt như thế này, đặc biệt là với ràng buộc về tính duy nhất, đó là cơn ác mộng về bảo trì khi xử lý trường hợp hai vị trí tham chiếu đến cùng một điểm, chưa kể đến việc dọn dẹp các hàng không được tham chiếu.
araqnid

2
> Chắc hẳn bạn không muốn có một bảng tọa độ riêng như thế này - Không hề? Không bao giờ? Bạn sẽ lưu trữ nó trong 1 trường như thế nào? Còn hàng triệu người KHÔNG sử dụng kiểu Spatial của SQL 2008 thì sao?
Sally

2
Có sự ràng buộc như vậy là một quyết định tồi. Giả sử Bob sống House Avà sẽ chuyển đến House B, ngôi nhà nơi Alice từng sống. Chẳng bao lâu nữa Bob sẽ không thể lưu địa chỉ (vị trí) của mình, vì Alice chưa cập nhật địa chỉ của cô ấy - hoặc sẽ không bao giờ.
jweyrich

@Sally - đó không phải là những gì anh ấy nói. Đọc bình luận của anh ấy. Ông cho biết không có lý do gì để lưu trữ một cặp giá trị riêng biệt bảng . Chỉ cần đặt vĩ độ / kinh độ trên bảng gốc và lưu chi phí của bảng thứ hai và tất cả các JOINS.
NickG
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.