20

Używam danych przestrzennych SQL Server 2008. Mam tabelę ze wszystkimi państwami (jako wielokątów) jako typ danych GEOMETRY. Teraz chcę sprawdzić, czy współrzędne punktu (szerokości i długości) jako typ danych GEOGRAFIA są w tym stanie, czy nie.SQL Server 2008 Spatial: znajdź punkt w wielokącie

Nie mogłem znaleźć żadnego przykładu przy użyciu nowych typów danych przestrzennych. Obecnie mam obejście, które zostało wdrożone wiele lat temu, ale ma pewne wady.

Mam zarówno SQL Server 2008 i 2012. Jeśli nowa wersja ma pewne ulepszenia, mogę zacząć w niej pracować.

Dzięki.

UPDATE 1:

dodaję próbkę kodu do nieco większej jasności.

declare @s geometry --GeomCol is of this type too. 
declare @z geography --GeogCol is of this type too. 

select @s = GeomCol 
from AllStates 
where STATE_ABBR = 'NY' 

select @z = GeogCol 
from AllZipCodes 
where ZipCode = 10101 
+0

To wydajność jest słaba, jeśli mają ogromne rekordy w bazie danych, próbowałem to zapytanie ponad 1600000 ewidencji i zajęło średnio 2 minuty kompletny. –

Odpowiedz

26

myślę, że STIntersects metoda geografii() zrobi co chcesz:

DECLARE @g geography; 
DECLARE @h geography; 
SET @g = geography::STGeomFromText('POLYGON((-122.358 47.653, -122.348 47.649, -122.348 47.658, -122.358 47.658, -122.358 47.653))', 4326); 
SET @h = geography::Point(47.653, -122.358, 4326) 

SELECT @g.STIntersects(@h) 
+0

Dzięki. Ale mój wielokąt, Stany, jest w typie danych GEOMETRIA. Czy powinienem najpierw zmienić ją na zmienną GEOGRAFIA? – Farhan

+0

Ah ... whoops. Tęskniłem za tą częścią tego. Czy jest jakiś powód, że twoje stany (dane geograficzne) są przechowywane jako dane geometryczne? –

+0

W rzeczywistości nie ma ku temu powodu. Kiedy przechodziłem przez kilka samouczków, po prostu założyłem, że typ danych GEOGRAFIA jest dla współrzędnych/punktów, a GEOMETRIA dla regionów/wielokątów. – Farhan

2

Jeśli nie można zmienić typu danych za przechowywane wielokątów do GEOGRAPHY potem można przekonwertować swobodę wejścia i długość geograficzna do GEOMETRY i użyj wartości STContains lub STIntersects względem wartości przekonwertowanej.

DECLARE @PointGeography GEOGRAPHY = geography::Point(43.365267, -80.971974, 4326) 
DECLARE @PointGeometry GEOMETRY = geometry::STGeomFromWKB(@PointGeography.STAsBinary(), 4326); 

SELECT @PolygonGeometry.STContains(@PointGeometry); 

Idąc w przeciwnym kierunku - próbuje przekształcić GEOMETRY wielokątów do GEOGRPAHY - jest podatny na błędy i prawdopodobnie nie uda z mojego doświadczenia.

i zauważ, że jeśli starają się stworzyć punkt GEOMETRY bezpośrednio od wartości szerokości i długości geograficznej wtedy STContains (lub STIntersects) nie zadziała (czyli nie dadzą mecz kiedy powinien).

0
declare @g geometry 
set @g=geometry::STGeomFromText('POLYGON((-33.229869 -70.891988, -33.251124 -70.476616, -33.703094 -70.508045, -33.693931 -70.891052,-33.229869 -70.891988))',0) 

DECLARE @h geometry; 

SET @h = geometry::STGeomFromText('POINT(-33.3906300 -70.5725020)', 0); 
SELECT @g.STContains(@h); 
0
  1. Nie należy mieszanie geometrii i geografii. Geometria jest dla PŁASKICH PLANÓW, Geografia dla SPHEROIDÓW (takich jak Ziemia).
  2. Należy "uzgodnić" kody SRID, aby sobie z tym poradzić. Każdy identyfikator SRID (na przykład 2913 = NZG2000) opisuje relację transformacji. Każdy identyfikator SRID może być użyty do odwzorowania do/z jednolitej sfery, czyli w jaki sposób przechodzisz od jednego do drugiego.
  3. Dopóki nie otrzymasz "tego samego" numeru SRID dla obu wartości, wiele dla funkcji .STxXX zwróci wartość NULL (możesz mieć wartość 0 w obu przypadkach)
  4. Jeśli nie są one takie same, ale udajesz, że są, możesz mieć błędy w skrajnych przypadkach.
  5. Jeśli wydasz trochę czasu "precalc", możesz określić górny/lewy i dolny/prawy punkt dla zaangażowanych rectów (i zapisać je) i użyć tych wartości w indeksach, aby ograniczyć rekordy do sprawdzenia. ile AT/L < BB/R i AB/R> BT/L nie mogą się pokrywać, co oznacza prostą 4 i numeryczne czek w twojej gdzie ograniczyć STWithin sprawdza

Oto przykład użyłem w SRID 2193.Wszystkie drogi w obrębie 3km promieniu danym punkcie, a wewnątrz określonej strefy szkolnej

DECLARE @g geometry 

SELECT @g = GEO2193 FROM dbo.schoolzones WHERE schoolID = 319 

SELECT DD.full_road_name, MIN(convert(int, dd.address_number)), MAX(convert(int, dd.address_number)) 
FROM (

select A.* from dbo.[street-address] A 

WHERE (((A.Shape_X - 1566027.50505) * (A.Shape_X - 1566027.50505)) + ((A.Shape_Y - 5181211.81675) * (A.Shape_Y - 5181211.81675))) < 9250000 

and a.shape_y > 5181076.1943481788 

and a.shape_y < 5185097.2169968253 

and a.shape_x < 1568020.2202472512 

and a.shape_x > 1562740.328937705 

and a.geo2193.STWithin(@g) = 1 
) DD 
GROUP BY DD.full_road_name 
ORDER BY DD.full_road_name