20

Sto utilizzando i tipi di dati spaziali di SQL Server 2008. Ho una tabella con tutti gli stati (come poligoni) come tipo di dati GEOMETRIA. Ora voglio controllare se le coordinate di un punto (latitudini, longitudini) come tipo di dati GEOGRAFIA, si trovano all'interno di quello stato oppure no.SQL Server 2008 Spatial: trova un punto nel poligono

Non sono riuscito a trovare alcun esempio utilizzando i nuovi tipi di dati spaziali. Attualmente, ho una soluzione alternativa che è stata implementata molti anni fa, ma presenta alcuni inconvenienti.

Ho entrambi SQL Server 2008 e 2012. Se la nuova versione ha alcuni miglioramenti, posso iniziare a lavorarci anche io.

Grazie.

UPDATE 1:

sto aggiungendo un esempio di codice per un po 'più di chiarezza.

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

la sua prestazione è scarsa se si dispone di enormi record nel database, ho provato questo query su 1600000 record e ci sono voluti avg 2 minuti per completare. –

risposta

26

Credo che i STIntersects metodo geografia() farà quello che vuoi:

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

Grazie. Ma il mio poligono, Stati, è in un tipo di dati GEOMETRY. Dovrei prima cambiarlo in una variabile GEOGRAFIA? – Farhan

+0

Ah ... whoops. Ho perso quella parte di esso. C'è una ragione per cui i tuoi stati (dati geografici) sono archiviati come dati geometrici? –

+0

In realtà, non c'è motivo per questo. Mentre stavo esaminando alcuni tutorial, ho assunto che il tipo di dati GEOGRAFIA sia per coordinate/punti e GEOMETRIA sia per regioni/poligoni. – Farhan

2

Se non è possibile modificare il tipo di dati per i poligoni memorizzati per GEOGRAPHY Quindi è possibile convertire la latitudine di ingresso e di longitudine a GEOMETRY e utilizzare lo STContains o STIntersects rispetto al valore convertito.

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

SELECT @PolygonGeometry.STContains(@PointGeometry); 

Andando nella direzione opposta - cercando di convertire i GEOMETRY poligoni per GEOGRPAHY - è soggetto a errori e probabilità di fallire dalla mia esperienza.

e si noti che se si tenta di creare il punto GEOMETRY direttamente dai valori di latitudine e longitudine poi il STContains (o STIntersects) non funziona (vale a dire non darà una corrispondenza quando dovrebbero).

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. Non si dovrebbe essere mescolando geometria e geografia. La geometria è per gli PIANI PIATTI, la Geografia è per gli SPERIDI (come la Terra).
  2. È necessario "riconciliare" gli SRID per risolvere il problema. Ogni SRID (ad esempio 2913 = NZG2000) descrive una relazione di trasformazione. Ogni SRID può essere usato per mappare a/da una sfera uniforme, che è il modo in cui si ottiene da uno all'altro.
  3. Fino ad arrivare ad una "stesso" SRID su entrambi i valori, molti per le funzioni .STxXX torneranno NULL (si potrebbe avere di default 0 in entrambi i casi)
  4. Se essi non sono la stessa cosa, ma si finta che sono, potresti avere errori sui casi limite.
  5. Se si trascorre del tempo "precalc", è possibile determinare i punti superiore/sinistro e inferiore/destro per i limiti di delimitazione coinvolti (e memorizzarli) e utilizzare tali valori negli indici per limitare i record da controllare. A meno che AT/L < BB/R e AB/R> BT/L non possono sovrapporsi, il che significa che un semplice 4 e numerici di controllo nel vostro DOVE limiterà la vostra STWithin controlla

Ecco un esempio che ho usato in SRID 2193.Tutte le strade nel raggio di un dato punto 3 km, e all'interno di una zona specifica scuola

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