5

Biorąc pod uwagę następujące dane, byłoby to możliwe, a jeśli tak, to który byłby najbardziej skuteczny sposób określania, czy położenie „Shurdington” w pierwszej tabeli jest zawarty w podane promienie dowolnego z miejsc w drugiej tabeli.jest punktem w promieniu geograficznej - SQL Server 2008

Kolumna GEODATA jest typu „geografii” typu, tak pomocą serwerów SQL właściwości przestrzennych są możliwe, jak również za pomocą długości i szerokości geograficznej.

Location  GeoData  Latitude Longitude 
=========================================================== 
Shurdington XXXXXXXXXX 51.8677979 -2.113189 

ID Location   GeoData  Latitude Longitude Radius 
============================================================================== 
1000 Gloucester  XXXXXXXXXX 51.8907127 -2.274598 10 
1001 Leafield  XXXXXXXXXX 51.8360519 -1.537438 10 
1002 Wotherton  XXXXXXXXXX 52.5975151 -3.061798 5 
1004 Nether Langwith XXXXXXXXXX 53.2275276 -1.212108 20 
1005 Bromley   XXXXXXXXXX 51.4152069 0.0292294 10 

Każda pomoc jest bardzo doceniana.

Odpowiedz

8

utworzyć dane

CREATE TABLE #Data (
    Id int, 
    Location nvarchar(50), 
    Latitude decimal(10,5), 
    Longitude decimal(10,5), 
    Radius int 
) 

INSERT #Data (Id,Location,Latitude,Longitude,Radius) VALUES 
(1000,'Gloucester', 51.8907127 ,-2.274598 , 20), -- Increased to 20 
(1001,'Leafield', 51.8360519 , -1.537438 , 10), 
(1002,'Wotherton', 52.5975151, -3.061798 , 5), 
(1004,'Nether Langwith', 53.2275276 , -1.212108 , 20), 
(1005,'Bromley', 51.4152069 , 0.0292294 , 10) 

test

stwierdzenie swój punkt zainteresowania jako POINT

DECLARE @p GEOGRAPHY = GEOGRAPHY::STGeomFromText('POINT(-2.113189 51.8677979)', 4326); 

Aby dowiedzieć się, czy to jest w promieniu innego punktu:

-- First create a Point. 
DECLARE @point GEOGRAPHY = GEOGRAPHY::STGeomFromText('POINT(-2.27460 51.89071)', 4326); 
-- Buffer the point (meters) and check if the 1st point intersects 
SELECT @point.STBuffer(50000).STIntersects(@p) 

Łącząc to wszystko w jednym zapytaniu:

select *, 
     GEOGRAPHY::STGeomFromText('POINT('+ 
      convert(nvarchar(20), Longitude)+' '+ 
      convert(nvarchar(20), Latitude)+')', 4326) 
     .STBuffer(Radius * 1000).STIntersects(@p) as [Intersects] 
from #Data 

Daje:

Id   Location Latitude Longitude Radius Intersects 
1000 Gloucester 51.89071 -2.27460 20 1 
1001 Leafield 51.83605 -1.53744 10 0 
1002 Wotherton 52.59752 -3.06180 5 0 
1004 Nether Langwith 53.22753 -1.21211 20 0 
1005 Bromley   51.41521 0.02923   10 0 

Re: Wydajność. Z pewnym poprawnego indeksowania wydaje indeksy przestrzenne SQL mogą być bardzo szybkie

+0

Uwielbiam ten przykład, chociaż dziwne, odległości wydają się być całkiem spore - może wynika to z mojego braku wiedzy na temat cech przestrzennych SQL Servera, ale nawet tak, przypuszczałem, że dodając kolumna ".STDistance (@p)/1609.34" zwróciłaby odległość w milach, wydaje się jednak odległa - czy to ja? – Nathan

+0

Wyliczyłem, że podczas tworzenia "PUNKTU" z "STGeomFromText" wymagane jest, aby długość/szerokość wprowadzana była w drugą stronę, np. długi/lat. – Nathan

+0

@Nathan Masz rację, będę aktualizować moją odpowiedź odpowiednio – Paddy

1

obliczyć odległość między dwoma punktami i porównać ten dystans w danym promieniu.

Do obliczania krótkich odległości można użyć wzoru na Wikipedia - Geographical distance - Spherical Earth projected to a plane, który twierdzi, że jest "bardzo szybki i daje dość dokładny wynik na małych odległościach".

Według wzoru, trzeba różnicę w szerokości i długości geograficznej oraz średnią szerokość geograficzną

with geo as (select g1.id, g1.latitude as lat1, g1.longitude as long1, g1.radius, 
        g2.latitude as lat2, g2.longitude as long2 
      from geography g1 
      join geography g2 on g2.location = 'shurdington' 
           and g1.location <> 'shurdington') 
    base as (select id, 
        (radians(lat1) - radians(lat2)) as dlat, 
        (radians(long1) - radians(long2)) as dlong, 
        (radians(lat1) + radians(lat2))/2 as mlat, radius 
       from geo) 
    dist as (select id, 
        6371.009 * sqrt(square(dlat) + square(cos(mlat) * dlong)) as distance, 
        radius 
       from base) 
select id, distance 
from dist 
where distance <= radius 

użyłem with select s jako etapów pośrednich, aby zachować obliczenia „czytelny”.

+0

Dlaczego to się dzieje, biorąc pod uwagę, że "używanie funkcji przestrzennych SQL Server jest opcją"? – AakashM

+0

@AakashM Ponieważ to było interesujące ćwiczenie. –

1

Jeśli chcesz zrobić matematyki siebie, można użyć equirectangular przybliżenie oparciu Pitagorasa. Wzór jest następujący:

zmienna x = (lon2-lon1) * Math.cos ((lat1 + lat2)/2); var y = (lat2-lat1); var d = Math.sqrt (x * x + y * y) * R;

chodzi o SQL, to powinno dać te lokalizacje w swojej 2nd tabeli zawierające wpis w 1. w ich promieniu:

SELECT * 
FROM Table2 t2 
WHERE EXISTS (
SELECT 1 FROM Table1 t1 
WHERE 
    ABS (
    SQRT (
    (SQUARE((RADIANS(t2.longitude) - RADIANS(t1.longitude)) * COS((RADIANS(t2.Latitude) + RADIANS(t1.Latitude))/2))) + 
    (SQUARE(RADIANS(t1.Latitude) - RADIANS(t2.Latitude))) 
    ) * 6371 --Earth radius in km, use 3959 for miles 
    ) 
    <= t2.Radius 
) 

Należy pamiętać, że to nie jest to najbardziej dokładna metoda jest dostępna, ale jest prawdopodobne, dobry dość. Jeśli patrzysz na odległości rozciągające się na całym świecie, możesz chcieć zastosować formułę Google "haversine".

Warto porównać to z rozwiązaniem Paddy'ego, aby zobaczyć, jak dobrze się zgadzają i które najlepiej się sprawdzają.

Powiązane problemy