Apa cara terbaik untuk menyimpan koordinat (bujur / lintang, dari Google Maps) di SQL Server?

103

Saya merancang tabel di SQL Server 2008 yang akan menyimpan daftar pengguna dan koordinat Google Maps (bujur & lintang).

Apakah saya membutuhkan dua bidang, atau dapatkah dilakukan dengan 1?

Apa tipe data terbaik (atau paling umum) yang digunakan untuk menyimpan jenis data ini?

Jonathan
sumber

Jawaban:

63

Peringatan Adil! Sebelum mengambil saran untuk menggunakan tipe GEOGRAFI, pastikan Anda tidak berencana menggunakan Linq atau Entity Framework untuk mengakses data karena tidak didukung (per November 2010) dan Anda akan sedih!

Perbarui Juli 2017

Bagi mereka yang membaca jawaban ini sekarang, jawaban ini sudah usang karena mengacu pada tumpukan teknologi yang sudah ketinggalan zaman. Lihat komentar untuk lebih jelasnya.

dan90266
sumber
1
Sejak jawaban asli diposting, saya menemukan artikel ini jasonfollas.com/blog/archive/2010/02/14/… membahas solusi yang mungkin.
Norman H
56
Peringatan tidak lagi valid. EF sekarang mendukung tipe Geografi.
Marcelo Mason
1
Nerveless EF mendukung Jenis Spasial, ia menggunakan jenis yang berbeda yang diatur ke Layanan Data WCF, sehingga tidak ada yang kompatibel
abatishchev
1
hibernate 5 spasial tidak diam misalnya :(
Eugene
1
Peringatan Adil masih berlaku Entity Framework Core 2.0 github.com/aspnet/EntityFrameworkCore/issues/1100
ono2012
29

Saya tidak tahu jawaban untuk SQL Server tetapi ...

Di MySQL, simpan sebagaiFLOAT( 10, 6 )

Ini adalah rekomendasi resmi dari dokumentasi pengembang Google .

CREATE TABLE `coords` (
  `lat` FLOAT( 10, 6 ) NOT NULL ,
  `lng` FLOAT( 10, 6 ) NOT NULL ,
) ENGINE = MYISAM ;
powtac.dll
sumber
19
Pertanyaannya dengan jelas menyatakan SQL Server, bukan MySQL. Dan Anda tentunya tidak akan menginginkan meja dengan hanya garis lintang dan bujur saja seperti itu.
araqnid
2
Setuju-jawaban yang buruk. Gunakan tipe spasial GEOGRAFI baru.
Pure.Krome
2
Tautan juga telah dipindahkan, ke code.google.com/apis/maps/articles/phpsqlajax.html
Ralph Lavelle
14
Saya tidak akan menggunakan float karena masalah presisi. Gunakan desimal (9,6).
kaptan
Ada kasus aktual di mana latdan lngmengungguli georgraphy, bahkan dengan indeks kepadatan tinggi di SQL 2014. Misalnya: menemukan semua titik dalam persegi panjang. Hanya saja saya tidak yakin, saya melihat bahwa Google Maps sekarang menggunakan 7, bukan 6 digit?
Nenad
22

Cara saya melakukannya: Saya menyimpan lintang dan bujur dan kemudian saya memiliki kolom ketiga yang merupakan tipe geografi turunan otomatis dari dua kolom pertama. Tabelnya terlihat seperti ini:

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

Ini memberi Anda fleksibilitas kueri spasial di kolom geoPoint dan Anda juga bisa mengambil nilai lintang dan bujur saat Anda membutuhkannya untuk ditampilkan atau diekstrak untuk tujuan csv.

jaxxbo.dll
sumber
bagus untuk apa yang saya cari, apakah Anda memiliki sesuatu untuk trek / jalur
aggie
Pendekatan lain yang juga dapat berfungsi, bergantung pada skenario Anda, adalah menyimpan bujur dan lintang, dan kemudian secara dinamis membuat objek geografi dengan cepat saat runtime.
Zapnologica
1
Ide bagus tetapi ketahuilah bahwa Anda tidak dapat membuat indeks spasial pada kolom yang dihitung jika itu adalah niat seseorang.
hvaughan3
1
@ hvaughan3 Saya rasa Anda bisa jika Anda menjadikannya kolom terhitung yang bertahan .
NickG
2
Terima kasih dan +1, jawaban Anda membantu saya. Tapi saya pikir akan lebih baik untuk digunakan Pointdaripada STGeomFromText. Sebagai contoh: [geography]::Point([Latitude], [Longitude], 4326).
default.kramer
21

Saya benci menjadi pelawan bagi mereka yang mengatakan "ini adalah tipe baru, mari kita gunakan". Jenis spasial SQL Server 2008 yang baru memiliki beberapa kelebihan - yaitu efisiensi, namun Anda tidak dapat secara membabi buta mengatakan selalu menggunakan jenis itu. Itu benar-benar tergantung pada beberapa masalah gambaran yang lebih besar.

Sebagai contoh, integrasi. Tipe ini memiliki tipe yang setara di .Net - tapi bagaimana dengan interop? Bagaimana dengan mendukung atau memperluas versi .Net? Bagaimana dengan mengekspos jenis ini di seluruh lapisan layanan ke platform lain? Bagaimana dengan normalisasi data - mungkin Anda tertarik pada informasi lintang atau bujur sebagai informasi yang berdiri sendiri. Mungkin Anda sudah menulis logika bisnis yang kompleks untuk menangani long / lat.

Saya tidak mengatakan bahwa Anda tidak boleh menggunakan tipe spasial - dalam banyak kasus Anda harus menggunakannya. Saya hanya mengatakan Anda harus mengajukan beberapa pertanyaan kritis sebelum menempuh jalan itu. Agar saya dapat menjawab pertanyaan Anda dengan paling akurat, saya perlu tahu lebih banyak tentang situasi spesifik Anda.

Menyimpan panjang / lintang secara terpisah atau dalam tipe spasial keduanya merupakan solusi yang layak, dan satu mungkin lebih disukai daripada yang lain tergantung pada keadaan Anda sendiri.

R. Lawson
sumber
GIS dan pengolahan data spasial memiliki sejarah panjang dan teks standar, representasi biner setidaknya sejak tahun 2000-an. Anda akan mendapatkan semua masalah yang Anda sebutkan jika Anda tidak menggunakan tipe spasial dan representasi standar
Panagiotis Kanavos
15

Yang ingin Anda lakukan adalah menyimpan Latitude dan Longitude sebagai tipe Spasial SQL2008 yang baru -> GEOGRAPHY.

Ini screen shot dari sebuah tabel, yang saya punya.

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

Dalam tabel ini, kami memiliki dua bidang yang menyimpan data geografi.

  • Batas: ini adalah poligon yang merupakan batas kode pos
  • CentrePoint: ini adalah titik Lintang / Bujur yang mewakili titik tengah visual dari poligon ini.

Alasan utama mengapa Anda ingin menyimpannya ke database sebagai tipe GEOGRAFI adalah agar Anda dapat memanfaatkan semua metode SPASIAL darinya -> mis. Titik di Poly, Jarak antara dua titik, dll.

BTW, kami juga menggunakan Google Maps API untuk mengambil data lintang / bujur dan menyimpannya di DB Sql 2008 kami - jadi metode ini berfungsi.

Pure.Krome
sumber
1
Dan bagaimana jika Anda belum di tahun 2008, atau bagaimana jika Anda menggunakan SQLCE? Yang terakhir tidak mendukung tipe GEOGRAFI ...
fretje
3
Jika SqlCE atau <2008 mendukung biner, dimungkinkan untuk menyimpan hasil varbinary dan kemudian menggunakan dll Spatial tools library untuk melakukan perhitungan spasial terhadap representasi data biner ini dalam kode NET Anda. Bukan solusi terbaik, tetapi masih merupakan solusi yang mungkin untuk beberapa masalah. (nuget untuk sql spasial .. untuk mengambil dll itu).
Pure.Krome
2
Tautan gambar rusak
Bryan Denny
urgh :( terima kasih untuk apa-apa, imageshack. Saya sudah tidak menggunakan IS selama bertahun-tahun :( imgur.com sepenuhnya!
Pure.Krome
1
-1, jawaban ini tidak lengkap tanpa gambar. Harap pertimbangkan untuk menggantinya dengan gambar baru atau deskripsi tabel tekstual, atau menghapus jawaban ini.
Ilmari Karonen
11

SQL Server memiliki dukungan untuk informasi terkait spasial. Anda dapat melihat lebih lanjut di http://www.microsoft.com/sqlserver/2008/en/us/spatial-data.aspx .

Sebagai alternatif, Anda dapat menyimpan informasi sebagai dua bidang dasar, biasanya pelampung adalah tipe data standar yang dilaporkan oleh sebagian besar perangkat dan cukup akurat dalam satu atau dua inci - lebih dari cukup untuk Google Maps.

Rosstified
sumber
2

CATATAN : Ini adalah jawaban terbaru berdasarkan SQL server terbaru, pembaruan tumpukan .NET

latitute dan longitude dari Google Maps harus disimpan sebagai data Point (note capital P) di SQL server dengan tipe data geografi.

Dengan asumsi data Anda saat ini disimpan dalam tabel Samplesebagai varchar di bawah kolom latdan lon, di bawah kueri akan membantu Anda mengonversi ke geografi

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

PS: Lain kali ketika Anda melakukan seleksi pada tabel ini dengan data geografi, selain dari tab Hasil dan Pesan, Anda juga akan mendapatkan tab hasil Spasial seperti di bawah ini untuk visualisasi

Tab hasil geo SSMS

DhruvJoshi
sumber
0

Jika Anda menggunakan Entity Framework 5 <Anda dapat menggunakan DbGeography. Contoh dari 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

Sesuatu yang saya perjuangkan kemudian saya mulai gunakan DbGeographyadalah coordinateSystemId. Lihat jawaban di bawah untuk penjelasan dan sumber yang sangat baik untuk kode di bawah ini.

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
sumber
-4

Jika Anda hanya akan menggantinya menjadi URL, saya kira satu bidang akan melakukannya - sehingga Anda dapat membentuk URL seperti

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

tetapi karena ini adalah dua bagian data, saya akan menyimpannya di bidang terpisah

Kristen
sumber
Ini kasus saya. Saya perlu menyimpan koordinat hanya dalam satu bidang dan dipisahkan dengan koma. Saya pikir seseorang bisa menggunakan TEXT sebagai tipe bidang. Bagaimana menurut anda?
Amr
-10

Simpan keduanya sebagai float, dan gunakan kata kunci unik di atasnya. I.em

create table coordinates(
coord_uid counter primary key,
latitude float,
longitude float,
constraint la_long unique(latitude, longitude)
);
Graviton
sumber
Untuk memastikan bahwa hanya ada 1 set unik pasangan lintang dan bujur. Anda tidak ingin menyimpan koordinat {0,0} dua kali di tabel Anda, bukan?
Graviton
1
Anda mungkin tidak ingin memiliki tabel koordinat terpisah seperti ini sama sekali, terutama dengan kendala keunikan, ini adalah mimpi buruk pemeliharaan jika dua lokasi merujuk ke titik yang sama, belum lagi membersihkan baris yang tidak direferensikan.
araqnid
2
> Anda mungkin tidak ingin memiliki tabel koordinat terpisah seperti ini sama sekali - Tidak sama sekali? Tidak pernah? Bagaimana Anda menyimpannya dalam 1 bidang? Bagaimana dengan jutaan orang yang TIDAK menggunakan tipe Spasial SQL 2008?
Sally
2
Memiliki kendala seperti itu adalah keputusan yang buruk. Misalkan Bob tinggal House A, dan akan pindah ke House B, rumah tempat Alice dulu tinggal. Bob segera tidak akan dapat menyimpan alamatnya (lokasi), karena Alice belum mengupdatenya - atau tidak akan pernah.
jweyrich
@ Sally - bukan itu yang dia katakan. Baca komentarnya. Dia mengatakan seharusnya tidak ada alasan untuk menyimpan sepasang nilai dalam tabel terpisah . Letakkan saja lintang / bujur pada tabel asli dan simpan overhead tabel kedua dan semua GABUNG.
NickG