วิธีใดที่ดีที่สุดในการจัดเก็บพิกัด (ลองจิจูด / ละติจูดจาก Google Maps) ใน SQL Server


103

ฉันกำลังออกแบบตารางใน SQL Server 2008 ที่จะจัดเก็บรายชื่อผู้ใช้และ Google Maps Co-ordinate (ลองจิจูดและละติจูด)

ฉันต้องการสองช่องหรือสามารถทำได้ด้วย 1?

ชนิดข้อมูลที่ดีที่สุด (หรือที่พบบ่อยที่สุด) ที่จะใช้ในการจัดเก็บข้อมูลประเภทนี้คืออะไร

คำตอบ:


54

ดูประเภทข้อมูลเชิงพื้นที่ใหม่ที่เปิดตัวใน SQL Server 2008 ซึ่งได้รับการออกแบบมาสำหรับงานประเภทนี้และทำให้การจัดทำดัชนีและการสืบค้นง่ายขึ้นและมีประสิทธิภาพมากขึ้น

ข้อมูลมากกว่านี้:


63

คำเตือนที่เป็นธรรม! ก่อนที่จะรับคำแนะนำในการใช้ประเภท GEOGRAPHY ตรวจสอบให้แน่ใจว่าคุณไม่ได้วางแผนที่จะใช้ Linq หรือ Entity Framework เพื่อเข้าถึงข้อมูลเนื่องจากไม่ได้รับการสนับสนุน (ณ เดือนพฤศจิกายน 2010) และคุณจะต้องเสียใจ!

อัปเดตกรกฎาคม 2560

สำหรับผู้ที่อ่านคำตอบนี้ในตอนนี้ถือว่าล้าสมัยเนื่องจากอ้างถึงสแต็คเทคโนโลยีที่ล้าสมัย ดูความคิดเห็นสำหรับรายละเอียดเพิ่มเติม


1
เนื่องจากมีการโพสต์คำตอบเดิมฉันพบบทความนี้jasonfollas.com/blog/archive/2010/02/14/…กำลังพูดถึงวิธีแก้ปัญหาที่เป็นไปได้
Norman H

56
คำเตือนใช้ไม่ได้อีกต่อไป EF รองรับประเภทภูมิศาสตร์แล้ว
Marcelo Mason

1
Nerveless EF รองรับ Spatial types โดยใช้การตั้งค่าประเภทต่างๆเป็น WCF Data Services จึงไม่สามารถใช้งานร่วมกันได้
abatishchev

1
ไฮเบอร์เนต 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 ;

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 หลัก?
เณรนาด

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


ยอดเยี่ยมสำหรับสิ่งที่ฉันกำลังมองหาคุณมีอะไรสำหรับแทร็ก / ไลน์
ไหม

อีกวิธีหนึ่งที่สามารถใช้ได้เช่นกันขึ้นอยู่กับสถานการณ์ของคุณคือการจัดเก็บ long และ lat จากนั้นเพียงแค่สร้างวัตถุทางภูมิศาสตร์แบบไดนามิกทันทีที่รันไทม์
Zapnologica

1
ความคิดที่ดี แต่โปรดทราบว่าคุณไม่สามารถสร้างดัชนีเชิงพื้นที่ในคอลัมน์ที่คำนวณได้หากเป็นความตั้งใจของใครบางคน
hvaughan3

1
@ hvaughan3 ฉันคิดว่าคุณทำได้ถ้าคุณทำให้มันเป็นคอลัมน์ที่คำนวณต่อเนื่อง
NickG

2
ขอบคุณและ +1 คำตอบของคุณช่วยฉัน แต่ผมคิดว่ามันจะดีกว่าที่จะใช้แทนPoint STGeomFromTextตัวอย่างเช่น: [geography]::Point([Latitude], [Longitude], 4326).
default.kramer

21

ฉันเกลียดที่จะตรงกันข้ามกับคนที่พูดว่า "ที่นี่เป็นแบบใหม่มาใช้กันเถอะ" ประเภทเชิงพื้นที่ SQL Server 2008 ใหม่มีข้อดีบางประการนั่นคือประสิทธิภาพ แต่คุณไม่สามารถพูดแบบสุ่มสี่สุ่มห้าใช้ประเภทนั้นได้เสมอไป มันขึ้นอยู่กับปัญหาภาพใหญ่บางประเด็นจริงๆ

ตัวอย่างเช่นการรวม ประเภทนี้มีประเภทเทียบเท่าใน. Net - แล้ว interop ล่ะ? แล้วการสนับสนุนหรือขยาย. Net เวอร์ชันเก่าล่ะ? แล้วการเปิดเผยประเภทนี้ในชั้นบริการไปยังแพลตฟอร์มอื่น ๆ ล่ะ สิ่งที่เกี่ยวกับการทำให้ข้อมูลเป็นมาตรฐาน - บางทีคุณอาจสนใจ lat หรือ long เป็นข้อมูลเดี่ยว ๆ บางทีคุณได้เขียนตรรกะทางธุรกิจที่ซับซ้อนเพื่อจัดการ long / lat แล้ว

ฉันไม่ได้บอกว่าคุณไม่ควรใช้ประเภทเชิงพื้นที่ - ในหลาย ๆ กรณีคุณควร ฉันแค่บอกว่าคุณควรถามคำถามที่สำคัญกว่านี้ก่อนที่จะไปตามเส้นทางนั้น เพื่อให้ฉันตอบคำถามของคุณได้ถูกต้องที่สุดฉันต้องการทราบข้อมูลเพิ่มเติมเกี่ยวกับสถานการณ์เฉพาะของคุณ

การจัดเก็บ long / lat แยกกันหรือในประเภทเชิงพื้นที่เป็นทั้งโซลูชันที่ทำงานได้และวิธีหนึ่งอาจดีกว่าสำหรับอีกแบบขึ้นอยู่กับสถานการณ์ของคุณเอง


GIS และการประมวลผลข้อมูลเชิงพื้นที่มีประวัติอันยาวนานและการแสดงข้อความมาตรฐานแบบไบนารีตั้งแต่ยุค 2000 เป็นอย่างน้อย คุณจะจบลงด้วยปัญหาทั้งหมดที่คุณกล่าวถึงหากคุณไม่ใช้ประเภทเชิงพื้นที่และการแสดงมาตรฐาน
Panagiotis Kanavos

15

สิ่งที่คุณต้องการทำคือจัดเก็บละติจูดและลองจิจูดเป็น SQL2008 Spatial type ใหม่ -> GEOGRAPHY

นี่คือภาพหน้าจอของตารางที่ฉันมี

ข้อความแสดงแทน http://img20.imageshack.us/img20/6839/zipcodetable.png

ในตารางนี้เรามีสองฟิลด์ที่เก็บข้อมูลภูมิศาสตร์

  • ขอบเขต: นี่คือรูปหลายเหลี่ยมที่เป็นขอบเขตรหัสไปรษณีย์
  • CentrePoint: นี่คือจุดละติจูด / ลองจิจูดที่แสดงถึงจุดกึ่งกลางภาพของรูปหลายเหลี่ยมนี้

สาเหตุหลักที่คุณต้องการบันทึกลงในฐานข้อมูลเป็นประเภท GEOGRAPHY คือเพื่อให้คุณสามารถใช้ประโยชน์จากวิธีการพิเศษทั้งหมดได้ -> เช่น ชี้ในโพลีระยะห่างระหว่างจุดสองจุด ฯลฯ

BTW เรายังใช้ Maps API ของ Google เพื่อดึงข้อมูล lat / long และจัดเก็บไว้ใน Sql 2008 DB ของเราดังนั้นวิธีนี้จึงใช้ได้ผล


1
และจะเกิดอะไรขึ้นถ้าคุณยังไม่ได้ใช้ในปี 2008 หรือถ้าคุณใช้ SQLCE ล่ะ? หลังไม่รองรับประเภท GEOGRAPHY ...
fretje

3
หาก SqlCE หรือ <2008 รองรับไบนารีเป็นไปได้ที่จะจัดเก็บผลลัพธ์ที่เป็นตัวแปรจากนั้นใช้ห้องสมุด Spatial tools dll เพื่อทำการคำนวณเชิงพื้นที่เทียบกับการแสดงข้อมูลไบนารีในรหัส. NET ของคุณ ไม่ได้เป็นทางออกที่ดีที่สุด แต่ยังคงเป็นวิธีการแก้ปัญหาที่เป็นไปได้บางปัญหา (nuget สำหรับ sql spatial .. เพื่อคว้า dll นั้น)
Pure.Krome

2
ลิงก์รูปภาพเสีย
Bryan Denny

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 ล่าสุดการอัปเดตสแต็ก. NET

ละติจูดและลองจิจูดจาก Google Maps ควรจัดเก็บเป็นข้อมูล Point (note capital P) ในเซิร์ฟเวอร์ SQL ภายใต้ประเภทข้อมูลภูมิศาสตร์

สมมติว่าข้อมูลปัจจุบันของคุณถูกจัดเก็บในตาราง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


-4

หากคุณกำลังจะแทนที่เป็น URL ฉันคิดว่าช่องหนึ่งจะทำ - ดังนั้นคุณสามารถสร้าง URL เช่น

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

แต่เนื่องจากเป็นข้อมูลสองส่วนฉันจะเก็บไว้ในช่องแยกต่างหาก


นี่คือกรณีของฉัน ฉันต้องการเก็บพิกัดในช่องเดียวเท่านั้นและคั่นด้วยลูกน้ำ ฉันคิดว่าสามารถใช้ TEXT เป็นประเภทฟิลด์ได้ คุณคิดอย่างไร?
Amr

-10

จัดเก็บทั้งแบบลอยและใช้คำสำคัญที่ไม่ซ้ำกัน 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 Spatial type ล่ะ?
Sally

2
การมีข้อ จำกัด เช่นนี้เป็นการตัดสินใจที่ไม่ดี สมมติว่าบ็อบอาศัยอยู่House Aและจะย้ายไปHouse Bอยู่บ้านที่อลิซเคยอาศัยอยู่ อีกไม่นานบ็อบจะไม่สามารถบันทึกที่อยู่ (สถานที่) ของเขาได้เนื่องจากอลิซยังไม่ได้อัปเดตข้อมูลของเธอหรือจะไม่ทำเลย
jweyrich

@ แซลลี่ - นั่นไม่ใช่สิ่งที่เขาพูด อ่านความคิดเห็นของเขา เขากล่าวว่าควรจะมีเหตุผลที่จะเก็บคู่ของค่าในการแยกไม่มีตาราง เพียงใส่ lat / long บนตารางเดิมและบันทึกค่าโสหุ้ยของตารางที่สองและ JOINS ทั้งหมด
NickG
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.