I have a polygon WKT and turning it into a geography and am presented with two polgyons, but where they overlap there is a void.
I am trying to find markers that exist in any polygon in the string (lat long intersects). The issue is that this void that is created I am not being delivered markers that exist there when it is required.
IF OBJECT_ID('tempdb..#customPolygon') IS NOT NULL DROP TABLE #customPolygon
CREATE TABLE #customPolygon (geog GEOGRAPHY)
[![DECLARE #customPolygon geography = 'MULTIPOLYGON (((-122.31260682058497 41.7828672412252, -122.66803538233832 41.74189213171878, -123.0157152218382 41.67409631073075, -123.35191487435746 41.58021595697532, -123.67306979164175
41.461266240272025, -123.97583066087832 41.31852640120816, -124.25710598001243 41.15352132907401, -124.51409805934621 40.96800014522892, -124.74433194261869 40.763912348675035, -124.94567706168226 40.54338210199239,
-125.11636173536279 40.30868123071627, -125.25498087780294 40.06220148128715, -125.3604974831004 39.80642653665781, -125.4322385960062 39.543904229883005, -125.46988656305209 39.277219329961135, -125.4734663894492
39.008967205820475, -125.44333001234564 38.74172860785035, -125.38013825025583 38.47804574501649, -125.28484111194828 38.22039978159673, -125.1586570556347 37.971189832187214, -125.00305168962673 37.73271349727281,
-124.8197163058454 37.50714895406215, -124.61054654308778 37.296538597688055, -124.37762139148631 37.102774215181654, -124.12318267532315 36.9275836675835, -123.8496150891857 36.772519052867715, -123.55942681226277
36.638946322795874, -123.25523068653888 36.52803632929597, -122.93972591543192 36.44075727956827, -122.61568021845359 36.377868583149755, -122.28591236310895 36.339916078129036, -121.9532749859139 36.327228627297,
-121.62063760871888 36.339916078129036, -121.2908697533742 36.377868583149755, -120.96682405639588 36.44075727956827, -120.65131928528895 36.52803632929597, -120.34712315956506 36.638946322795874, -120.0569348826421
36.772519052867715, -119.78336729650465 36.9275836675835, -119.52892858034149 37.102774215181654, -119.29600342874002 37.29653859768806, -119.08683366598238 37.50714895406215, -118.90349828220107 37.73271349727281,
-118.7478929161931 37.971189832187214, -118.62170885987955 38.22039978159673, -118.52641172157198 38.47804574501649, -118.46321995948216 38.74172860785035, -118.43308358237861 39.008967205820475, -118.43666340877571
39.277219329961135, -118.4743113758216 39.543904229883005, -118.54605248872741 39.80642653665781, -118.65156909402486 40.06220148128715, -118.79018823646503 40.30868123071627, -118.96087291014557 40.54338210199239,
-119.16221802920913 40.763912348675035, -119.3924519124816 40.96800014522892, -119.6494439918154 41.15352132907401, -119.93071931094948 41.31852640120816, -120.23348018018605 41.461266240272025, -120.55463509747037 41.58021595697532, -120.89083474998958 41.67409631073075, -121.2385145894895 41.74189213171878, -121.59394315124284 41.7828672412252, -122.31260682058497 41.7828672412252)), ((-119.1795222467484 42.50521242789702, -120.70099431758788 39.07636493660857, -115.32512633395542 38.91870544294517, -119.1795222467484 42.50521242789702)))'
INSERT INTO #customPolygon
SELECT geography::STPolyFromText(#customPolygon, 4326).MakeValid().ToString()
UPDATE #customPolygon SET geog=case when geog.EnvelopeAngle() > 90 then geog.ReorientObject() else geog end
SET #customPolygonJoin = ' join #customPolygon poly on poly.geog.STIntersects(a.GeoLoc) = 1 '][1]][1]
I would like to avoid itemizing polygons within the multipolygon string as there could be an unlimited number.
I've tried ST unions and ST difference, except it seems those require two geography inputs, where the multipolgyon is just 1.
TYIA
I think this "hole" is artifact of your drawing tool. Within SQL Server, it is two overlapping polygons - so there is no hole, it is instead covered by both of the polygons.
But if you want to dissolve this into a single polygon, I would try to StUnion it with empty geography (geography::STGeomFromText('POLYGON EMPTY', 4326)) or with itself.
I use 2 ways if calculating distance between coordinates, difference between them is quite big (more than 400 m). Do you know why? And which one of all ways of calculating is the most accurate?
1st:
DECLARE #source geography = 'POINT(53.9202690124512 14.2586479187012)'
DECLARE #target geography = 'POINT(53.8970128 14.2387088)'
SELECT #source.STDistance(#target)
2nd:
SELECT geography::Point(53.9202690124512, 14.2586479187012, 4326).STDistance(geography::Point(53.8970128, 14.2387088, 4326))
geography::Point expects the latitude and longitude to be passed in that order. WKT's POINT expects longitude and latitude to be passed in that order. See the results of:
DECLARE #wkt_source geography = 'POINT(53.9202690124512 14.2586479187012)'
DECLARE #wkt_target geography = 'POINT(53.8970128 14.2387088)'
select #wkt_source.STAsText() as wkt_source, #wkt_target.STAsText() as wkt_target
declare #point_source geography = geography::Point(53.9202690124512, 14.2586479187012, 4326)
declare #point_target geography = geography::Point(53.8970128, 14.2387088, 4326)
select #point_source.STAsText() as point_source, #point_target.STAsText() as point_target
So you will need to swap one or other around to get consistent results (depending on which lat/lng is correct).
I have downloaded a shapefile from Ordinance Survey website, and imported it into SQL using ShpToSql.exe, here the setup
This imports fine.
Now i want to query what region a particular longitude and latitude is within.
Using the following
Postcode: WD25 7LR (Harry Potter Studios :D)
Latitude: 51.6910751568794
Longitude: -0.418128358906299
I thought i could write something like
DECLARE #g geography
set #g = geography::Point(51.6910751568794, -0.418128358906299, 4326)
select [name] from region where #g.STWithin(geom) is not null
But that returns an error message of Operand type clash: geometry is incompatible with geography
So i tried to change the data type to geometry, so code looks like this
declare #g geometry
set #g = geometry::Point(51.6910751568794, -0.418128358906299, 4326)
select [name] from region where #g.STWithin(geom) = 1
But no results are returned.
Can someone help me with this please. Just want to know if a longitude and latitude is within a particular POLYGON.
UPDATE:
I have tried to import the .shp file using Geography data type, but this gives an error message when i try to import it
And even if i still try to import it, i them get a message like this for every shape in the shp file
SQL Server will not allow comparisons between geometry and geography data types.
If you are not concerned with being exact, you could perform your original query with the point as a geometry type. This will work reasonably well in most small cases where you aren't comparing odd shapes and across hemispheres.
DECLARE #g geometry
set #g = geometry::Point(51.6910751568794, -0.418128358906299, 4326)
select [name] from region where #g.STWithin(geom) is not null
Otherwise you will need to import the data as a geography type and based on your note there might be some malformed data in the shapefile.
Given a point, how can I query SQL Server to find the stored polygons that encompass it?
I have a database table that has the polygons of all 50 US states. I need a query that will allow me to search for which states are within 90 miles of that point.
Here is my table structure and data for three states:
CREATE TABLE dbo.States (
State varchar(20) NOT NULL,
CoordinatorEmail varchar(255) NULL,
Borders geography(-1) NULL
);
INSERT INTO States (State, Borders)
VALUES ('Alaska', (geography::STGeomFromText('POLYGON((-141.0205 70.0187,-141.7291 70.1292,-144.8163 70.4515,-148.4583 70.7471,-151.1609 70.7923,-152.6221 71.1470,-153.9954 71.1185,-154.8853 71.4307,-156.7529 71.5232,-157.9449 71.2796,-159.6313 71.2249,-161.8671 70.6363,-163.5809 70.0843,-165.2399 69.3028,-166.8768 69.1782,-168.0414 68.3344,-165.9155 67.6844,-164.6082 67.2933,-164.0149 66.7789,-165.7507 66.5810,-167.5745 66.2867,-168.9862 66.0269,-168.9478 65.4970,-167.4756 65.0420,-167.0142 64.3922,-165.7343 64.0554,-163.2294 64.0193,-162.1143 63.9615,-163.6029 63.6877,-165.3717 63.4530,-166.3715 62.4133,-166.9867 61.6534,-166.4429 60.8556,-167.8381 60.5357,-167.7118 59.5482,-165.8002 59.4115,-164.5972 59.3696,-162.8558 59.1168,-162.5427 58.1185,-160.6421 58.1359,-159.5050 58.0285,-158.8953 57.6336,-159.9060 56.9090,-160.6531 56.3926,-161.8835 56.2342,-162.9822 55.7240,-164.3994 55.2478,-165.3168 54.7753,-167.1075 54.1463,-168.5852 53.5632,-169.9146 53.1402,-169.5959 52.5964,-168.2227 52.9089,-162.7734 54.2139,-159.1452 54.6786,-155.4634 55.6567,-152.1400 57.3510,-150.8203 59.2209,-147.4461 59.7695,-145.9850 60.3521,-144.1544 59.8917,-141.6811 59.8172,-140.5124 59.5225,-138.8548 59.0292,-136.8526 57.9032,-136.0725 56.9157,-134.9794 56.1555,-134.0057 55.3237,-133.6418 54.6341,-130.6261 54.7135,-129.9930 55.2869,-130.0108 55.9869,-130.1083 56.1057,-131.5887 56.6086,-132.8755 57.8404,-133.8423 58.7276,-134.9121 59.3108,-135.4724 59.8020,-136.3445 59.6039,-136.8251 59.1619,-137.6079 59.2441,-139.2119 60.0902,-139.0938 60.3575,-140.0056 60.1866,-140.9999 60.3059,-141.0205 70.0187,-141.0205 70.0187))', 4326)));
INSERT INTO States (State, Borders)
VALUES ('Alabama', (geography::STGeomFromText('POLYGON((-88.1955 35.0041,-85.6068 34.9918,-85.1756 32.8404,-84.8927 32.2593,-85.0342 32.1535,-85.1358 31.7947,-85.0438 31.5200,-85.0836 31.3384,-85.1070 31.2093,-84.9944 31.0023,-87.6009 30.9953,-87.5926 30.9423,-87.6256 30.8539,-87.4072 30.6745,-87.3688 30.4404,-87.5240 30.1463,-88.3864 30.1546,-88.4743 31.8939,-88.1021 34.8938,-88.1721 34.9479,-88.1461 34.9107,-88.1955 35.0041))', 4326)));
INSERT INTO States (State, Borders)
VALUES ('Arkansas', (geography::STGeomFromText('POLYGON((-94.0416 33.0225,-91.2057 33.0075,-91.1989 33.1180,-91.1041 33.1824,-91.1343 33.3053,-91.1646 33.4211,-91.2263 33.4337,-91.2524 33.5403,-91.1797 33.6112,-91.2524 33.6855,-91.1261 33.6946,-91.1412 33.7883,-91.0451 33.7700,-91.0341 33.8328,-91.0863 33.9399,-90.9256 34.0208,-90.9036 34.0856,-90.9586 34.1345,-90.9132 34.1675,-90.8501 34.1380,-90.9325 34.2311,-90.6935 34.3446,-90.5603 34.4409,-90.5548 34.5348,-90.5768 34.5959,-90.5301 34.7213,-90.5328 34.7574,-90.4546 34.8780,-90.3529 34.8454,-90.2911 34.8690,-90.3104 35.0255,-90.2843 35.1154,-90.1772 35.1323,-90.1112 35.1985,-90.1524 35.2826,-90.1332 35.4383,-90.0206 35.5579,-89.9780 35.6740,-89.9547 35.7287,-89.6594 35.9169,-89.6883 35.9658,-89.7130 36.0013,-90.3735 35.9958,-90.2664 36.1268,-90.0934 36.2875,-90.0742 36.3892,-90.1511 36.4180,-90.1566 36.4997,-94.6198 36.4986,-94.4412 35.3801,-94.4893 33.6318,-94.4522 33.6421,-94.4000 33.5597,-94.2462 33.5883,-94.1885 33.5872,-94.0375 33.5345,-94.0430 33.4314,-94.0430 33.0213,-94.0416 33.0225))', 4326)));
I have been trying the following query just to make sure I can get the state of the point (without yet worrying about the 90 mile radius), but I haven't figure this part out yet.
DECLARE #LittleRock geography;
SET #LittleRock = geography::Point(34.742000, -92.276543, 4326);
Select State from States
where States.Borders.STIntersects(#LittleRock) = 1;
SELECT State from States
where States.Borders.STContains(#LittleRock) = 1;
Neither STIntersets() nor STContains() returns anything. Thoughts?
When I ran your code on my local instance, I got the following error (abbreviated):
This operation cannot be completed because the instance is not valid.
Use MakeValid to convert the instance to a valid instance.
Next, I did what the robot told me to do:
UPDATE dbo.States
SET Borders = Borders.MakeValid();
Once that was done, I was able to determine that Little Rock is indeed in Arkansas with both STIntersects() and STContains(). So there was something malformed in at least one of your geography instances.
EDIT
Given the OPs full data set, it has another issue with some of the states. Specifically, 21 states appear to have a ring orientation problem. With Geography polygons, the order in which you specify the vertexes is important. I never remember whether clockwise or counter-clockwise is the right direction. But I do remember the heuristic I use. If the envelope angle for the polygon is greater than 90°, I probably got it wrong. Luckily, that is also easy to correct for.
UPDATE s
SET s.Borders = s.Borders.ReorientObject()
FROM dbo.States AS s
WHERE s.Borders.EnvelopeAngle() > 90
With the raw data set, your Little Rock query returns 22 states. With the update above run, it returns only Arkansas.
Environment: SQL Server 2012
I'm using an online tool, the only one I could find so far, to plot polygons and points on the earth. http://www.birdtheme.org/useful/googletool.html
I have two tables. One stores "areas" as polygons and the other table stores points amongst other things irrelevant to my question.
For simplicity, I'll just reduce my scenario to sql variables.
In the query below, I'm using the geography data type for well known points of interest.
I drew a polygon around Robben Island, a point in Robben Island and a point in Alcatraz.
DECLARE #robben_island geography = ('POLYGON((18.351803 -33.788421,18.382788 -33.787494,18.386736 -33.820515,18.354464 -33.822369,18.351803 -33.788421))')
DECLARE #point_in_robben_island geography= ('POINT(18.369226 -33.80554)')
DECLARE #point_in_alcatraz geography= ('POINT(-122.423401 37.827006)')
SELECT #robben_island.STContains(#point_in_robben_island) --returns 'False', but it's not what I expected
SELECT #robben_island.STContains(#point_in_alcatraz) --returns 'True', but it's not what I expected
This query above, if I understand it correctly, tells me that my #point_in_robben_island is not contained in #robben_island, rather my #point_in_alcatraz exists in #robben_island which as we all know, is not true.
Now when I change the data types from geography to geometry, everything works fine, but I'm afraid that if I continue using the geometry data type I might come across a few gotchas. I'm just wondering if I won't be negatively affected by fact that geometry doesn't quite account for earth's curvature. touch wood.
DECLARE #robben_island geometry = ('POLYGON((18.351803 -33.788421,18.382788 -33.787494,18.386736 -33.820515,18.354464 -33.822369,18.351803 -33.788421))')
DECLARE #point_in_robben_island geometry= ('POINT(18.369226 -33.80554)')
DECLARE #point_in_alcatraz geometry= ('POINT(-122.423401 37.827006)')
SELECT #robben_island.STContains(#point_in_robben_island) --returns 'True' as it should
SELECT #robben_island.STContains(#point_in_alcatraz) --returns 'False' as it should
Now my question is, why does the geography data type return unexpected results while geometry works as expected? Thank you very much.
The geography type is a little bit more restrictive than geometry. It can't cross different hemispheres and the outer ring must be drawn counter-clockwise.
Unfortunately (some find this a good thing), SQL Server 2012 no longer throws an error when you create the invalid geography. You need to invert the order of the points in the Roben Island geometry, like:
DECLARE #robben_island geography = ('POLYGON((18.351803 -33.788421, 18.354464 -33.822369,18.386736 -33.820515, 18.382788 -33.787494, 18.351803 -33.788421))')
DECLARE #point_in_robben_island geography= ('POINT(18.369226 -33.80554)')
DECLARE #point_in_alcatraz geography= ('POINT(-122.423401 37.827006)')
SELECT #robben_island.STContains(#point_in_robben_island) --returns 'True'
SELECT #robben_island.STContains(#point_in_alcatraz) --returns 'False'