I am trying to query a MySQL database (version 5.7.15) to retrieve all locations that are within 300 meters from some coordinates (40.7542, -73.9961 in my case):
SELECT *
FROM location
WHERE st_distance_sphere(latlng, POINT(40.7542, -73.9961)) <= 300
From the MySQL documentation:
ST_Distance_Sphere(g1, g2 [, radius])
Returns the mimimum spherical distance between two points and/or
multipoints on a sphere, in meters, or NULL if any geometry argument
is NULL or empty.
Unfortunately, the query also returns points that are more than 300 meters away from POINT(40.7542, -73.9961) such as:
POINT(40.7501, -73.9949) (~ 470 meters in real life)
POINT(40.7498, -73.9937) (~ 530 meters in real life)
Note that in MySql the order of coordinates are:
1. POINT(lng, lat) - no SRID
2. ST_GeomFromText('POINT(lat lng)', 4326) - with SRID
select st_distance_sphere(POINT(-73.9949,40.7501), POINT( -73.9961,40.7542))
will return 466.9696023582369, as expected, and 466.9696023582369 > 300 of course
Just to make it clear for future people (like myself):
Mituha Sergey has answered the question in comments on the OP. The problem was that OP was using POINT(lat, lng) when in fact MySQL expects POINT(lng, lat).
Not sure about the time OP posted the question, but as of today the official documentation makes it a bit clearer:
The geometry arguments should consist of points that specify
(longitude, latitude) coordinate values:
Longitude and latitude are the first and second coordinates of the point, respectively.
Both coordinates are in degrees.
Longitude values must be in the range (-180, 180]. Positive values are east of the prime meridian.
Latitude values must be in the range [-90, 90]. Positive values are north of the equator.
From: https://dev.mysql.com/doc/refman/5.7/en/spatial-convenience-functions.html#function_st-distance-sphere
And if you're getting "invalid arguments" errors it's probably because of that. Try adding WHERE lat between -90 and 90 AND lng between -180 and 180 just to be on the safe side haha :)
Related
I try to get some approximate distance between 2 points in mariaDB.
I use that SQL:
SELECT st_distance(POINT(50.6333,3.0667),p) from p
It outputs results such as:
0
1.9128040446888426
8.103248262271125
It seems mariaDB does not handle SRID.
Is there a way to convert these values to km ? (looks like multiplying by 110 is quite correct)
My goal is to avoid handling maths such as sin, cos, atan and approximate result is ok for me.
The result returned by st_distance are not kilometer but minutes.
For a circumference of the equator of d = 40.075km, the distance between two minutes is d / 360 = 111,319 km.
While the distance between the latitudes is constant, the distance between the longitudes from the equator to the pole caps decreases constantly. According to your example the point from one location must be somewhere in France, where the distance between longitudes is around 70km.
Since you don't want to use the Haversine formula, you can also use the Pythagorean theorem to get a more accurate result:
# Distance between Eiffel tower and Lille
SELECT ST_DISTANCE(GeomFromText("Point(50.6333 3.0669)"), GeomFromText("Point(48.853. 2.348)")) * 111.38;
-> 213.84627307672486
select sqrt(pow((50.63333 - 48.853) * 111.38,2) + pow((3.0669 - 2.348) * 70, 2));
->204.57903071304386
ST_DISTANCE is designed for flat-earth advocates.
ST_DISTANCE_SPHERE is available in InnoDB as of 5.7.
https://dev.mysql.com/doc/refman/5.7/en/spatial-convenience-functions.html#function_st-distance-sphere
select *
from zones z
where st_intersects(z.geom, st_Buffer(ST_SetSRID(ST_Point( 2.336031, 48.863172), 3857),1));
It looks like the '1' in the st_buffer is being interpreted as degrees, I need to find geometries within n meters of a given point.
I did find a reference to a new function (st_Buffer_Meters) but that didn't seem to do anything different.
The actual query that ended up working was:
select nom
from zones s
where ST_DWITHIN(Geography(ST_Transform(s.geom,4326)), ST_Point($1, $2) ,$3);`
Where $1 is Longitude, $2 is Latitude and $3 is distance in meters.
In addition I changed my imported data from SRID 3857 to SRID 4326
Here's the gis.stackexchange question: https://gis.stackexchange.com/questions/118472/postgis-get-geometries-within-a-radius-of-n-meters-using-wgs84/118476#118476
And here's the 'This has been asked before link https://gis.stackexchange.com/questions/77688/postgis-get-the-points-that-are-x-meters-near-another-point-in-meters
First, I simplified your query to use a distance function, which will do the same thing as your query performs with fewer words. ST_Distance_Sphere will return the minimum distance between two geometries in meters. However I had some difficulty in using your SRID so I use ST_Transform to transform the SRID to 4326
select *
from zones z
where st_distance_sphere(z.geom,
ST_TRANSFORM(ST_SetSRID(ST_Point( 2.336031, 48.863172), 3857), 4326
)< 1000;
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.
I need to calculate the distance between two points, but not in the regular way. I need to know 'the east to west distance' + 'the north to south distance'. I guess this is more simple then the regular 'as the crow flies' calculation but i still can't figure out how to do it.
I want to do this using a MySQL query and preferably have the result returned in km. One of the points will be a constant in the query and the other point is a point from the DB so something like SELECT abs(longitude-39.12345)...+abs(latitude... AS Distance FROM shops WHERE shopname='Bingo'.
Thanks in advance!
The north-to-south distance is proportional to the difference in the latitudes. It's about 1 nautical mile per minute of arc (the circumference of the earth is about 21600 nautical miles).
The east-to-west distance is proportional to the difference in the longitudes, but it also varies with the latitude (e.g. it's zero at the poles): I think it's proportional to the cosine of latitude.
Your answer depends on the accuracy required in your answer. If you don't need an answer more accurate than a spherical earth model, you can use a solution similar to the one given by Captain Tom. If you require more accuracy, you'll need to assume the earth is an oblate spheroid. See http://en.wikipedia.org/wiki/Vincenty%27s_formulae for a couple of solutions.
The east-west difference between two points at different latitudes is a distinct number in degrees of longitude, but converting this to miles is problematic because the miles per degree vary according to the latitude. For example, Los Angles and New York City are 44.3 degrees of longitude apart, but converting this to miles would result in a larger number at LA's latitude than at NYC's latitude, since latitude lines are longest at the equator and shrink to zero at the poles.
A reasonable convention would be to count the E-W distance as the average of the two distances calculated at the two latitudes.
You can determine the distance between any two geocode points using the Great-Circle Distance. Here is another decent article on the subject.
The following is an example in C# which shows how to do this:
var earth_radius = Constants.EarthRadius; // 6377.8 km
var dLat = ToRadians(fromLatitude - toLatitude);
var dLon = ToRadians(fromLongitude - toLongitude);
var a =
Math.Sin(dLat / 2) *
Math.Sin(dLat / 2) +
Math.Cos(ToRadians(fromLatitude)) *
Math.Cos(ToRadians(toLatitude)) *
Math.Sin(dLon / 2) *
Math.Sin(dLon / 2);
var c = 2 * Math.Asin(Math.Min(1, Math.Sqrt(a)));
var distanceInKilometers = earth_radius * c;
Use simple trig. The normal "as the crow flies" distance is the hypotenuse of the right triangle formed with the two points you have in mind at either ends of the hypotenuse.
Just look at this http://en.wikipedia.org/wiki/Hypotenuse and the solution should become clear.
Is there a convention for whether GIS points in MySQL should be stored as POINT($latitude $longitude) or POINT($longitude $latitude)?
Having longitude correspond to X on a cartesian map would visually make more sense with north pointing up, but common parlance is to say "latitude and longitude."
In MySQL you will probably use the GeomFromText() function to insert data in a spatial field. This function uses the WKT (Well-Known Text) format to define the geometries, and in the POINT case, it is defined as:
POINT ($longitude $latitude)
The accepted answer is NOT CORRECT for working with GPS coordinates in MySQL 8+ and it will get into trouble (haven't tested it with previous version of MySQL).
TL;DR; Use 'POINT($lat $long)' as WKT string but POINT($long, $lat) with the POINT() function in MySQL 8+.
Full answer:
Using WKT notation as 'POINT($longitude $latitude)' while using SRID 4326 (the one you should use for GPS coordinates system) leads to incorrect distance calculations even if consistently used throughout the app. Read on for details.
For example, let's consider the direct distance between CN Tower in Toronto and One World Trade Center in NYC which is approx. 549,18km according to Google Maps.
GPS coordinates:
CN Tower: 43.64386666880877, -79.38670551139633
One World Trade Centre: 40.689321781458446, -74.04415571126154
Expected distance: 549.18km
Following query yields the correct result:
SELECT
ST_DISTANCE(
ST_GEOMFROMTEXT('POINT(40.689321781458446 -74.04415571126154)', 4326),
ST_GEOMFROMTEXT('POINT(43.64386666880877 -79.38670551139633)', 4326),
'metre'
)
FROM DUAL;
-- results in 549902.432032006 meters which is around 549.9km (CORRECT)
However, if you provide longitude first in your WKT (as suggested in the accepted answer) you get a wrong distance calculated:
SELECT
ST_DISTANCE(
ST_GEOMFROMTEXT('POINT(-74.04415571126154 40.689321781458446)', 4326),
ST_GEOMFROMTEXT('POINT(-79.38670551139633 43.64386666880877)', 4326),
'metre'
)
FROM DUAL;
-- results in 601012.8595500318 which is around 601km (WRONG)
As you can see the POINT($long $lat) WKT string approach is incorrect and is off by approx. 51km compared to POINT($lat $long) approach which is almost 10% error. And it actually gets worse the farther you go.
Explanation:
It seems to happen because when MySQL considers a WKT string in the context of GPS coordinates it considers first argument as latitude and the second one as longitude. Try running the following query:
SELECT
ST_Latitude(ST_GEOMFROMTEXT('POINT(40.689321781458446 -74.04415571126154)',4326)) as latitude,
ST_Longitude(ST_GEOMFROMTEXT('POINT(40.689321781458446 -74.04415571126154)',4326)) as longitude
FROM dual;
-- results in
latitude, longitude
40.689321781458446,-74.04415571126154
Beware though, that the opposite is true when using the POINT(x, y) function instead of a WKT string!
Example:
SELECT
ST_DISTANCE(
ST_SRID(POINT(-74.04415571126154, 40.689321781458446), 4326),
ST_SRID(POINT(-79.38670551139633, 43.64386666880877), 4326),
'metre'
)
FROM DUAL;
-- results in 549902.432032006 meters which is around 549.9km (CORRECT)