दो बिंदुओं के बीच की दूरी की गणना (अक्षांश, देशांतर)


88

मैं एक मानचित्र पर दो पदों के बीच की दूरी की गणना करने की कोशिश कर रहा हूं। मैंने अपने डेटा में संग्रहीत किया है: देशांतर, अक्षांश, एक्स पीओएस, वाई पीओएस।

मैं पहले नीचे दिए गए स्निपेट का उपयोग कर रहा हूं।

DECLARE @orig_lat DECIMAL
DECLARE @orig_lng DECIMAL
SET @orig_lat=53.381538 set @orig_lng=-1.463526
SELECT *,
    3956 * 2 * ASIN(
          SQRT( POWER(SIN((@orig_lat - abs(dest.Latitude)) * pi()/180 / 2), 2) 
              + COS(@orig_lng * pi()/180 ) * COS(abs(dest.Latitude) * pi()/180)  
              * POWER(SIN((@orig_lng - dest.Longitude) * pi()/180 / 2), 2) )) 
          AS distance
--INTO #includeDistances
FROM #orig dest

हालाँकि मुझे इससे निकलने वाले आंकड़ों पर भरोसा नहीं है, यह थोड़ा गलत परिणाम देता है।

कुछ नमूना डेटा के मामले में आपको इसकी आवश्यकता है

Latitude        Longitude     Distance 
53.429108       -2.500953     85.2981833133896

क्या कोई मेरे कोड के साथ मेरी मदद कर सकता है, मुझे कोई आपत्ति नहीं है यदि आप ठीक करना चाहते हैं जो मेरे पास पहले से ही है यदि आपके पास इसे प्राप्त करने का एक नया तरीका है जो बहुत अच्छा होगा।

कृपया बताएं कि आपके परिणामों की माप किस इकाई में है।


आपको अतिरिक्त / 2 द्वारा साइन करने के तर्क को विभाजित नहीं करना चाहिए। इसके अलावा आप पृथ्वी त्रिज्या में अधिक सटीकता के साथ-साथ जीपीएस सिस्टम (डब्ल्यूजीएस -84) द्वारा उपयोग किए जाने वाले कुछ डेटाम का उपयोग कर सकते हैं जो पृथ्वी को एक दीर्घवृत्त (भूमध्य रेखा और ध्रुवों पर अलग-अलग
रेडी द्वारा

@Aller, आप इसे प्राप्त करने के लिए भूगोल / ज्यामिति (स्थानिक) प्रकार का उपयोग क्यों नहीं करते?
हबीब

3
मैंने गणितज्ञ के साथ आपकी गणना की जाँच की; यह सोचता है कि क़ानून मील (5280 फीट) में दूरी 42.997 है, जो बताती है कि आपकी गणना थोड़ी गलत नहीं है , बल्कि यह बेतहाशा गलत है
उच्च प्रदर्शन मार्क

जवाबों:


128

चूंकि आप SQL Server 2008 का उपयोग कर रहे हैं, आपके पास geographyडेटा प्रकार उपलब्ध है, जो इस तरह के डेटा के लिए डिज़ाइन किया गया है:

DECLARE @source geography = 'POINT(0 51.5)'
DECLARE @target geography = 'POINT(-3 56)'

SELECT @source.STDistance(@target)

देता है

----------------------
538404.100197555

(1 row(s) affected)

हमें बता रहे हैं कि यह एडिनबर्ग से लंदन (पास) से लगभग 538 किमी (करीब) दूर है।

स्वाभाविक रूप से पहले करने के लिए सीखने की एक मात्रा होगी, लेकिन एक बार जब आप जानते हैं कि यह अपने खुद के हैवरसिन गणना को लागू करने से कहीं अधिक आसान है; साथ ही आपको बहुत सारी कार्यक्षमता मिलती है।


यदि आप अपनी मौजूदा डेटा संरचना को बनाए रखना चाहते हैं, तब भी आप विधि का उपयोग करके STDistanceउपयुक्त geographyउदाहरणों का निर्माण करके उपयोग कर सकते हैं Point:

DECLARE @orig_lat DECIMAL(12, 9)
DECLARE @orig_lng DECIMAL(12, 9)
SET @orig_lat=53.381538 set @orig_lng=-1.463526

DECLARE @orig geography = geography::Point(@orig_lat, @orig_lng, 4326);

SELECT *,
    @orig.STDistance(geography::Point(dest.Latitude, dest.Longitude, 4326)) 
       AS distance
--INTO #includeDistances
FROM #orig dest

6
@nezam नहीं - देश के प्रमुख मेरिडियन के स्थानों के लिए देशांतर नकारात्मक होगा , और पूर्व के स्थानों के लिए सकारात्मक
आकाशवाणी

आपने मेरा दिन बचाया! .. बहुत बहुत धन्यवाद!
ध्रूमिल भानखार

1
अंतर्निहित फ़ंक्शन का उपयोग करना बहुत धीमी गति से लगता है। उदाहरण के लिए, 100,000 आइटम लूप में, मेरे उपयोगकर्ता परिभाषित फ़ंक्शन के लिए 1.4 सेकंड के बजाय 23 सेकंड लगते हैं (दुरई का जवाब देखें)।
NickG

1
बस स्थानिक अनुक्रमित + के लिए @AakashM की सिफारिश की पुष्टि करना और पुष्टि करना चाहता था ... ETL आवेदन के लिए, अंतर स्थानिक अनुक्रमित लागू करने के बाद बेहतर परिमाण के कई आदेश थे
बिल एंटोन

3
FYI करें: बिंदु (
लंबी

41

नीचे दिए गए फंक्शन मील में दो भू-आकृतियों के बीच दूरी प्रदान करते हैं

create function [dbo].[fnCalcDistanceMiles] (@Lat1 decimal(8,4), @Long1 decimal(8,4), @Lat2 decimal(8,4), @Long2 decimal(8,4))
returns decimal (8,4) as
begin
declare @d decimal(28,10)
-- Convert to radians
set @Lat1 = @Lat1 / 57.2958
set @Long1 = @Long1 / 57.2958
set @Lat2 = @Lat2 / 57.2958
set @Long2 = @Long2 / 57.2958
-- Calc distance
set @d = (Sin(@Lat1) * Sin(@Lat2)) + (Cos(@Lat1) * Cos(@Lat2) * Cos(@Long2 - @Long1))
-- Convert to miles
if @d <> 0
begin
set @d = 3958.75 * Atan(Sqrt(1 - power(@d, 2)) / @d);
end
return @d
end 

नीचे दिए गए फंक्शन किलोमीटर में दो भू-गर्भ के बीच दूरी तय करते हैं

CREATE FUNCTION dbo.fnCalcDistanceKM(@lat1 FLOAT, @lat2 FLOAT, @lon1 FLOAT, @lon2 FLOAT)
RETURNS FLOAT 
AS
BEGIN

    RETURN ACOS(SIN(PI()*@lat1/180.0)*SIN(PI()*@lat2/180.0)+COS(PI()*@lat1/180.0)*COS(PI()*@lat2/180.0)*COS(PI()*@lon2/180.0-PI()*@lon1/180.0))*6371
END

नीचे दिया गया कार्य भूगोल डेटा प्रकार का उपयोग करके किलोमीटर में दो भू-आकृतियों के बीच की दूरी प्रदान करता है जिसे एसक्यूएल सर्वर 2008 में पेश किया गया था

DECLARE @g geography;
DECLARE @h geography;
SET @g = geography::STGeomFromText('LINESTRING(-122.360 47.656, -122.343 47.656)', 4326);
SET @h = geography::STGeomFromText('POINT(-122.34900 47.65100)', 4326);
SELECT @g.STDistance(@h);

उपयोग:

select [dbo].[fnCalcDistanceKM](13.077085,80.262675,13.065701,80.258916)

संदर्भ: Ref1 , Ref2


2
मुझे विभिन्न घटनाओं के ज़िप कोड के लिए 35K ज़िप कोड के लिए दूरी की गणना करने की आवश्यकता है जो ज़िप कोड के लिए दूरी द्वारा आदेश दिया गया है। यह भूगोल डेटा प्रकार का उपयोग करके गणना करने के लिए निर्देशांक की एक सूची से बहुत बड़ा था। जब मैंने ऊपर एकल-पंक्ति ट्रिगर फ़ंक्शन आधारित समाधान का उपयोग करने के लिए स्विच किया, तो यह बहुत तेज़ी से चला। इसलिए भूगोल प्रकारों का उपयोग करके केवल दूरी की गणना करना महंगा प्रतीत होता है। सावधान ग्राहक।
टॉमबाला

क्वेरी के WHERE क्लॉज में दूरी की गणना के लिए बहुत उपयोगी है। मुझे "सेट @ डी =" अभिव्यक्ति के चारों ओर एक एबीएस () को लपेटना पड़ा, क्योंकि मुझे कुछ मामले मिले जहां फ़ंक्शन ने नकारात्मक दूरी वापस कर दी।
जो इर्बी

1
"किलोमीटर में दो भू-गर्भ के बीच की दूरी" के लिए फ़ंक्शन यदि हम 2 समान बिंदुओं की तुलना करते हैं, तो यह आपको त्रुटि देता है "एक अमान्य फ़्लोटिंग पॉइंट ऑपरेशन हुआ"
RRM

2
यह बहुत अच्छा था लेकिन छोटी दूरी के लिए काम नहीं करता क्योंकि "दशमलव (8,4)" पर्याप्त सटीकता प्रदान नहीं करता है।
प्रभावशाली

1
@influent सही है, यह छोटी दूरी के लिए उपयोगी नहीं है (मेरे मामले में 5 मील)
रोजर

15

ऐसा लगता है कि Microsoft ने अन्य सभी उत्तरदाताओं के दिमाग पर हमला किया और उन्हें यथासंभव जटिल समाधान लिखे। यहां बिना किसी अतिरिक्त कार्य के सबसे सरल तरीका है / बयान घोषित करें:

SELECT geography::Point(LATITUDE_1, LONGITUDE_1, 4326).STDistance(geography::Point(LATITUDE_2, LONGITUDE_2, 4326))

बस अपने डेटा स्थानापन्न के बजाय LATITUDE_1, LONGITUDE_1, LATITUDE_2, LONGITUDE_2जैसे:

SELECT geography::Point(53.429108, -2.500953, 4326).STDistance(geography::Point(c.Latitude, c.Longitude, 4326))
from coordinates c

2
संदर्भ के लिए: STDistance () स्थानिक संदर्भ प्रणाली के माप की रैखिक इकाई में दूरियां लौटाता है जिसमें आपका भूगोल डेटा परिभाषित होता है। आप SRID 4326 का उपयोग कर रहे हैं, जिसका अर्थ है कि STDistance () मीटर में दूरी लौटाता है।
ब्रायन स्टंप

4

जैसा कि आप SQL 2008 या बाद में उपयोग कर रहे हैं, मैं GEOGRAPHY डेटा प्रकार की जाँच करने की सलाह दूंगा । SQL ने भू-स्थानिक प्रश्नों के समर्थन में बनाया है।

उदाहरण के लिए, आपके पास GEOGRAPHY की अपनी तालिका में एक स्तंभ होगा, जो निर्देशांक के भू-स्थानिक प्रतिनिधित्व (उदाहरण के लिए ऊपर दिए गए MSDN संदर्भ की जाँच करें) के साथ आबाद होगा। यह डेटाटाइप तब विधियों को उजागर करता है जिससे आप भू-स्थानिक प्रश्नों की पूरी मेजबानी कर सकते हैं (जैसे 2 बिंदुओं के बीच की दूरी ज्ञात करना)


बस जोड़ने के लिए, मैंने भूगोल फ़ील्ड प्रकार की कोशिश की, लेकिन दुरई के फ़ंक्शन (सीधे देशांतर और अक्षांश मानों का उपयोग करते हुए) को अधिक तेज़ होने के लिए पाया। यहाँ मेरा उदाहरण देखें: stackoverflow.com/a/37326089/391605
माइक Gledhill

4
Create Function [dbo].[DistanceKM] 
( 
      @Lat1 Float(18),  
      @Lat2 Float(18), 
      @Long1 Float(18), 
      @Long2 Float(18)
)
Returns Float(18)
AS
Begin
      Declare @R Float(8); 
      Declare @dLat Float(18); 
      Declare @dLon Float(18); 
      Declare @a Float(18); 
      Declare @c Float(18); 
      Declare @d Float(18);
      Set @R =  6367.45
            --Miles 3956.55  
            --Kilometers 6367.45 
            --Feet 20890584 
            --Meters 6367450 


      Set @dLat = Radians(@lat2 - @lat1);
      Set @dLon = Radians(@long2 - @long1);
      Set @a = Sin(@dLat / 2)  
                 * Sin(@dLat / 2)  
                 + Cos(Radians(@lat1)) 
                 * Cos(Radians(@lat2))  
                 * Sin(@dLon / 2)  
                 * Sin(@dLon / 2); 
      Set @c = 2 * Asin(Min(Sqrt(@a))); 

      Set @d = @R * @c; 
      Return @d; 

End
GO

उपयोग:

dbo.DistanceKM (37.848832506474, 37.848732506474, 27.83935546875, 27.83905546875) का चयन करें

आउटपुट:

0,02849639

आप टिप्पणी किए गए फ़्लोट्स के साथ @ आर पैरामीटर बदल सकते हैं।


पूरी तरह से काम करता है
तेजस्वी हेगड़े 12

1

पिछले उत्तरों के अलावा, यहाँ एक SELECT के अंदर की दूरी की गणना करने का एक तरीका है:

CREATE FUNCTION Get_Distance
(   
    @La1 float , @Lo1 float , @La2 float, @Lo2 float
)
RETURNS TABLE 
AS
RETURN 
    -- Distance in Meters
    SELECT GEOGRAPHY::Point(@La1, @Lo1, 4326).STDistance(GEOGRAPHY::Point(@La2, @Lo2, 4326))
    AS Distance
GO

उपयोग:

select Distance
from Place P1,
     Place P2,
outer apply dbo.Get_Distance(P1.latitude, P1.longitude, P2.latitude, P2.longitude)

स्केलर फ़ंक्शन भी काम करते हैं लेकिन बड़ी मात्रा में डेटा की गणना करते समय वे बहुत अक्षम होते हैं।

मुझे उम्मीद है कि यह किसी की मदद कर सकता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.