I am just starting to work with spatial data in SQL Server (2008 r2). I am looking to calculate the distance between two coordinates (miles).
DECLARE #source geography
DECLARE #target geography
SET #source = geography::STGeomFromText('POINT (43.420026 -83.974472)', 4326);
SET #target = geography::STGeomFromText('POINT (43.458786 -84.029471)', 4326);
SELECT #source.STDistance(#target)/1609.344 -- meters to miles
My query results in a value of 3.827 miles but I checked it against the site linked below and they are returning a distance of 3.85 miles. Am I doing this incorrectly?
http://www.boulter.com/gps/distance/?from=43.420026+-83.974472&to=43.458786+-84.029471&units=m
I don't think you're doing anything wrong. Your SQL query looks reasonable to me. But…
I'm far from an expert on spatial reference systems and geodesic stuff (have you considered asking the expert folks over at GIS SE?); nevertheless, here's three possibilites that come to my mind:
Perhaps they calculate the distance along a straight line instead of the geodesic distance (i.e. the distance along a curved line, the Earth isn't flat after all). SQL Server's geography type should account for that.
This does not seem very plausible, given that "their" distance is greater than "yours": you'd expect straight-line distance to be smaller than geodesic distance.
Perhaps they can do the calculation more accurately than SQL Server (see note on the MSDN reference page for geography.STDistance):
"STDistance() returns the shortest LineString between two geography types. This is a close approximate to the geodesic distance. The deviation of STDistance() on common earth models from the exact geodesic distance is no more than .25%. This avoids confusion over the subtle differences between length and distance in geodesic types."
Or, both calculations are somewhat inaccurate, but in opposite directions. If I'm not mistaken, the two results you're citing differ by something like 0.5%, that could just be the sum of their deviation and SQL Server's.
But I could be completely wrong.
Related
I have a database with a bunch of LineString's and I want to see if a Point is within, say, 50ft of that line.
Since it's a LineString, expecting ST_CONTAINS to return true for a point that's even 1ft away from the LineString seems unlikely BUT if there was a way to add an accepted error margin that'd be cool.
Here's the query I did:
SELECT *
FROM railroads
WHERE ST_CONTAINS(SHAPE, ST_GeomFromText('POINT(-10874300.116373 3537642.0497826)', 3857));
Unsurprisingly, it returns no results.
Any ideas? I'm running MySQL 8.0.22.
You need a condition like
ST_Distance(shape, geo_constant) < distance.
Another pattern to do it is
ST_Intersect(shape, ST_Buffer(geo_constant, distance)).
Buffer is expensive, so make sure you buffer a single constant, not the table column.
But there is another issue here, you are using projection 3857, so the distance is in projection units, not feet or meters. If you care about precision, transform Geometry to Geography type.
MYSQL ver 5.7
Requirement:
I have a bunch of POINT geometries in MYSQL table and I have to find all the POINT geometries that are within 5km distance/radius of a GEOMETRYCOLLECTION object.
GEOMETRYCOLLECTION may contain more than one type of geometries like POINT, POLYGON etc.
Sample GEOMETRYCOLLECTION data:
SET #g1 = ST_GeomFromText('GEOMETRYCOLLECTION(POINT (-156.366489591715 66.913750389327),POLYGON ((-156.357608905242 66.906958164897, -156.360302383363 66.9066027336476, -156.361997104194 66.9067073607308, -156.363616093774 66.9066368440642, -156.365477697938 66.9065867326059, -156.368127298976 66.9065970034393, -156.370061891681 66.9066888794808, -156.37182258022 66.9068547305222, -156.373286981259 66.9070724523969, -156.374390675008 66.9072952721882, -156.376359777088 66.9077681138541, -156.377706173961 66.9080113180204, -156.379222192708 66.9081328753119, -156.380729601039 66.9081591586452, -156.382562289578 66.9081211961453, -156.387571662487 66.9099676951007, -156.389320598943 66.9125180930134, -156.389291120818 66.9145787836353, -156.384722634367 66.9167899596735, -156.37955035 66.9195246586276, -156.372520662511 66.9209119638337, -156.360432280238 66.9215118034161, -156.355776993787 66.9203754471679, -156.34906598338 66.9180659711298, -156.347941981299 66.9174007836309, -156.346853913592 66.9167568252985, -156.34605399901 66.9158971169665, -156.346982815675 66.9151925950926, -156.346794497967 66.9144321773854, -156.345642955261 66.9140107294695, -156.343831364638 66.9136152003034, -156.342996512556 66.9130307378043, -156.343113243806 66.9123137492637, -156.343498096931 66.9119029992644, -156.344661664637 66.9111819440571, -156.345080786511 66.9105884961414, -156.345524286511 66.9099605023924, -156.347168040675 66.9098486503092, -156.348952756297 66.9096090419763, -156.348689200048 66.9089614565606, -156.349495732338 66.908706844061, -156.350786711503 66.9082992794783, -156.352211271917 66.9083472388533, -156.353952768789 66.90829894302, -156.355389368787 66.9082072242701, -156.356512531285 66.9079768284371, -156.356677961493 66.9078075857291, -156.356422527119 66.907644261771, -156.355901372953 66.9072802273965, -156.357608905242 66.906958164897)))');
Sample POINT data:
SET #p1 = ST_GeomFromText('GEOMETRYCOLLECTION(POINT (-156.342840017 66.9320439348))');
I have tried ST_DISTANCE_SPHERE(#g1,#p1) spatial function (which returns the value in meters) but it seems it doesn't support geometry types other than POINT and MULTIPOINT.
Then I have used:
ST_DISTANCE(#g1,#p1)
'0.015301834064271899'
I am unable to understand the what is the UNIT of this returned value in MYSQL 5.7?
I have searched a lot on the internet and there is no proper documentation available regarding the same. In POSTGIS, this can be done but I am struggling to do this in MYSQL ver 5.7.
Any help is appreciated.
Thanks in advance!
ST_Distance returns "distance" in degrees here - i.e. the flat map view of the shortest distance between shapes. This value cannot be mapped to real distance, as real world distance of 1 degree along parallel is different from distance of 1 degree along meridian except near the equator.
Looks like MySQL cannot correctly compute distance here. You would be better served by systems with more geospatial support, like PostgreSQL + PostGIS, or Google BigQuery, etc. They give you correct answer, you just need to replace ST_GeomFromText with ST_GeogFromText to work with spherical geographies.
I have a SQL database set of places to which I am assigned coordinates (lat, long). I would like to ask those points that lie within a radius of 5km from my point inside. I wonder how to construct a query in a way that does not collect unnecessary records?
Since you are talking about small distances of about 5 km and we are probably not in the direct vicinity of the north or south pole we can work with an approximated grid system of longitude and latitude values. Each degree in latidude is equivalent to a distance of km_per_lat=6371km*2*pi/360degrees = 111.195km. The distance between two longitudinal lines that are 1 degree apart depends on the actual latitude:
km_per_long=km_per_lat * cos(lat)
For areas here in North Germany (51 degrees north) this value would be around 69.98km.
So, assuming we are interested in small distances around lat0 and long0 we can safely assume that the translation factors for longitudinal and latitudinal angles will stay the same and we can simply apply the formula
SELECT 111.195*sqrt(power(lat-#lat0,2)
+power(cos(pi()/180*#lat0)*(long-#long0),2)) dist_in_km FROM tbl
Since you want to use the formula in the WHERE clause of your select you could use the following:
SELECT * FROM tbl
WHERE 111.195*sqrt(power(lat-#lat0,2)
+power(cos(pi()/180*#lat0)*(long-#long0),2)) < 5
The select statement will work for latitude and longitude values given in degree (in a decimal notation). Because of that we have to convert the value inside the cos() function to radians by multiplying it with pi()/180.
If you have to work with larger distances (>500km) then it is probably better to apply the appropriate distance formula used in navigation like
cos(delta)=cos(lat0)*cos(lat)*cos(long-long0) + sin(lat0)*sin(lat)
After calculating the actual angle delta by applying acos() you simply multiply that value by the earth's radius R = 6371km = 180/pi()*111.195km and you have your desired distance (see here: Wiki: great circle distance)
Update (reply to comment):
Not sure what you intend to do. If there is only one reference position you want to compare against then you can of course precompile your distance calculation a bit like
SELECT #lat0:=51,#long0:=-9; -- assuming a base position of: 51°N 9°E
SELECT #rad:=PI()/180,#fx:=#rad*6371,#fy:=#fx*cos(#rad*#lat0);
Your distance calculation will then simplify to just
SELECT #dist:=sqrt(power(#fx*(lat-#lat0),2)+power(#fy*(long-#long0),2))
with current positions in lat and long (no more cosine functions necessary). It is up to you whether you want to store all incoming positions in the database first or whether you want to do the calculations somewhere outside in Spring, Java or whatever language you are using. The equations are there and easy to use.
I would go with Euklid. dist=sqrt(power(x1-x2,2)+power(y1-y2,2)) . It works everywhere. Maybe you have to add a conversion to the x/y-coordinates, if degrees can't be translated in km that easy.
Than you can go and select everything you like WHERE x IS BETWEEN (x-5) AND (x+5) AND y IS BETWEEN (y-5) AND (y+5) . Now you can check the results with Euklid.
With an optimisation of the result order, you can get better results at first. Maybe there's a way to take Euklid to SQL, too.
I'm trying to query any locations within a specified distance from another location. The query is not the problem, but the distance returned by geography.STDistance is.
It seems STDistance makes fairly accurate calculations on locations close to the equator, but I need this to work with locations in the nordic countries. Norway, Sweden, Finland and so on...
According to my calculations, made on locations in northern Sweden, the distance is wrong by a factor of around 2.38?!
Expected result is 1070 meters and returned distance is 2537,28850694302 meters
My query looks like this:
DECLARE #g geography = geography::STGeomFromText('POINT(65.580254 22.179428)', 4326)
SELECT name, [pos].STSrid as srdi, [pos].STDistance(#g) as d
FROM [GPSCHAT].[dbo].[USERS]
and the "other location" has coordinates (65,578541 22,202286) (stored with SRID 4326)
I'm guessing this has to do with the distance from the equator (close to the polar circle), but there has to be a way to calculate this more accurately based on the Latitude or am i wrong?
It looks like you're creating your point using 'X, Y'.
When creating a point from text, use 'Y, X' instead.
Check out this MSDN Article for some more info.
Why don't you make use of another spatial reference identifier which fits better the earth curvature around your position. SRID 4326 might not been measured as accurate as other local referential systems
I am trying to calculate distance between two locations using spatial functions in both Mysql and PostgresSQL. I have taken the latitude and longitude from Google. The details are below
Location one - Lat: 42.260223; Lon: -71.800010
Location two - Lat: 42.245647; Lon: -71.802521
SQL Query used:
SELECT DISTANCE(GEOMFROMTEXT('Point(42.260223 -71.800010)'),GEOMFROMTEXT('Point(42.245647 -71.802521)'))
The both databases are giving the same result 0.014790703059697. But when I calculate distance in other systems the results are different. Please refer the below links
http://www.zip-codes.com/distance_calculator.asp?zip1=01601&zip2=01610&Submit=Search = 1.44 miles
http://www.distancecheck.com/zipcode-distance.php?start=01601&end=01610 = 1.53 miles
So I want to know whether my calculation method/query is right or not. And if it is wrong, then what is the right way of querying the db for the distance.
The simple answer is to use the Haversine formula. This assumes the earth is a sphere, which it isn't, but it's not a bad approximation. This, with lots of other details are described in this presentation:
http://www.scribd.com/doc/2569355/Geo-Distance-Search-with-MySQL
In the case above, MySql is simply applying the pythagorean theorem: c2 = a^2 + b^2. In this specific case SQRT((42.245647 - 42.260223)^2 + (-71.802521^2 - -71.800010)^2) = 0.014790703.
There are actually two problems with using the MySql distance functon for distance with coordinates on a sphere. (1) MySql is caclulating distance on a plane, not a sphere. (2) The result is coming back in a form of degrees, not miles. To get a true, spherical distance in miles, km, ft etc, you need to convert your lat and long degrees into the units you want to measure by determining the radius from a line through the center of the earth for the latitude(s) you are measuring.
To get a true measure is quite complicated, many individuals and companies have made careers out of this.