Select items within range using MySQL spatial extensions? - mysql

I am completely new to MySQL spatial extensions, so please excuse my ignorance on the topic.
The scenario:
1) I collect a user's location via latitude and longitude. I store that location in a MySQL table.
2) I then display any other users within a range of that user. The range would be small - let's say 1000 ft.
Question:
What is the best practice for storing the location points? What is the best practice for querying and selecting the points nearest that user?

Use the POINT Spatial datatype to store the coordinates.
The structure is like this:
CREATE TABLE gps name varchar(0), `location` point NOT NULL;
Please note the type of column 'location'.
After that, you have to define a SPATIAL index for the 'location' column.
CREATE SPATIAL INDEX sp_index ON gps(`location`);
Inserting data (latitude and longitude)
INSERT INTO gps (name, location) VALUES ( 'India' , GeomFromText( ' POINT(31.5 42.2) ' ) )
The function GeomFromText takes a string and returns a Geometry Object. Here 31.5 and 42.2 are latitude and longitude respectively. Note that there is NO comma between them. They are delimited by a space.
Reading data
SELECT name, AsText(location) FROM gps;
The AsText function converts the internal representation of a geometry to a string format.
Note: You have to use MySQL 5.0 or above the spatial extension support. Also use 'MyIsam' db engine for faster queries.

Unfortunately there is no such function in MySQL as select points in radius. But you can easily use this cosine law formula: d = acos( sin(φ1)*sin(φ2) + cos(φ1)*cos(φ2)*cos(Δλ) )*R to get distance between 2 points. You can find details here: http://www.movable-type.co.uk/scripts/latlong-db.html
SQL query will look like this:
SELECT acos(sin(radians(Y(point1)))*sin(radians(Y(point2))) + cos(radians(Y(point1)))*cos(radians(Y(point2)))*cos(radians(X(point2))-radians(X(point1)))) * 6371 AS `distance`
FROM locations

Related

Error when attempting to use st_distance_sphere to filter rows in MySQL

I have a table with polygon geometries. I am attempting to filter rows based on proximity to a point.
I am using st_distance_sphere to calculate distance and filters rows: link
For a snapshot of mysql table, it's contents and what I am attempting to do, check out this link: https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=9e8bfca54f665f411453791c300c7fbd
When I run the query,
select *
from geo
where st_distance_sphere(Point(35.0872464,-106.6975887), ST_Centroid(`spatialdata`)) <= 1609*10;
I get an error:
Error Code: 3617. Latitude -106.646665 is out of range in function st_distance_sphere. It must be within [-90.000000, 90.000000].
I suppose I need to switch to Long, Lat axis order to calculate the distance. How do I do that in mysql?
What's a bit confusing is: MySQL has standardized all geometries to lat-long axis order. From the docs: The EPSG has standardized on latitude-longitude order, so all geographic SRSs defined by default in MySQL are latitude-longitude.
Doc link: https://dev.mysql.com/blog-archive/axis-order-in-spatial-reference-systems/
Reverse the order of the two constant numbers in the Point object in your query.
Point(-106.6975887, 35.0872464)

Create MySQL spatial column - Point Data type with lat long without using Alter table

How can I create a MySQL spatial column with "Point" Data type using latitude & longitude using a CREATE statement. (Without using Alter)
Do I need to store latitude and longitude as well or can I insert both values into the Point(x,y) field and get rid of the latitude/ longitude columns? The examples that I have read till now retain the lat long fields.
Please share some examples.
The point field has both the latitude and longitude data stored inside it and they can be retrieved quite easily if required. Assuming your point field is name pt, the following query gives this information.
SELECT ST_Y(pt), ST_X(pt) FROM my_spatial_table;
This is exactly the same as doing
SELECT Y(pt), X(pt) FROM my_spatial_table;
since X and ST_X are aliases. So in short you only need the point field.
You can add your pt field as follows:
ALTER TABLE my_table ADD COLUMN GEOMETRY;
Then you can move the data from the existing latitude, and longitude columns as follows:
UPDATE my_table SET pt = PointFromText(CONCAT('POINT(',longitude,' ',latitude,')'))
For more details on this please see: https://stackoverflow.com/a/7135890/267540
http://dev.mysql.com/doc/refman/5.7/en/populating-spatial-columns.html

SQL selecting spatial points

I am trying to select a spatial point in SQL so that I can receive the latitude and coordinate of the point in the most simple form possible.
Currently my query looks like this:
SELECT AsText(`coordinates`) FROM table
This returns something along the lines of:
POINT(53.432985 -1.357258)
Are there any other spatial functions that will allow me to return these as two seperate values or at least make them a little easier to perform something like substr on them?
Ideally I'd like it to return two values, a latitude value and a longitude value
This is the geospatial way to retrieve latitude/longitude from a POINT type, assuming that coordinates is stored as a POINT type. X will return the latitude and Y the longitude.
SELECT X(coordinates),Y(coordinates) FROM table
I assume your geometry field is called coordinates?
SELECT location.STY as Lat, location.STX as Lon from yourTableName
If it's a geography datatype try
SELECT location.Lat as Lat, location.Long as Lon from yourTablename

Latitude Longitude mysql query

i have a problem with this query:
SELECT city,6371 * ACos( Cos(RADIANS(Lat)) * Cos(RADIANS(51.166698)) * Cos(RADIANS(-1.7833) - RADIANS(Lng)) + Sin(RADIANS(Lat)) * Sin(RADIANS(51.166698)) ) AS Distance
FROM GeoPC
GROUP BY city ORDER BY Distance LIMIT 20
The query needs about 30 seconds. There are about 1.7 million rows in the database and the group by and the order by is too heavy for the database.
Any idea how i can fix it?
Have you tried moving the Distance parameter to a calculated field in the GeoPC table? On the face of it I can't see it making a massive difference but it's something quick to try.
Your using the Haversine function to calculate the distance between two points in the WGS84 geodetic coordinate system (e.g., lat/lng). MySQL supports geospatial types and functions which are much higher performance. You will need to replace the fields Lat, Lng (which I assume are of type decimal) with a single field of type POINT(). There are methods for walking through your table to do this. Once done, you can use MySQL's geospatial methods to calculate distance between two points. Here's a recent blog on the subject:
http://www.mysqlperformanceblog.com/2013/10/21/using-the-new-spatial-functions-in-mysql-5-6-for-geo-enabled-applications/
Here's the MySQL online documentation on geospatial types:
http://dev.mysql.com/doc/refman/5.0/en/mysql-spatial-datatypes.html

SQL Select Radius Search based on Latitude Longitude

I got 2 tables:
Events:
- id
- name
- place
Places:
- id
- name
- lat
- lng
I would like to retrieve all events that in 10KM radius (based on the place lat & lng) from the current lat and lng. How can I do that?
Thanks!
If you are willing to use an extension, the geospatial extension, in MySQL 5.6 and on, is intended to address exactly this type of question. You will need to build a spatial index on your places table:
ALTER TABLE places ADD SPATIAL INDEX lat, lng
select name from places
order by st_distance(point(#lng, #lat), point(lng, lat))
limit 10
The actual finding of actual distances is a bit computation heavy. The following post lays out some of the methods you might want to try: http://www.plumislandmedia.net/mysql/using-mysqls-geospatial-extension-location-finder/
For even more detail, look at http://www.percona.com/blog/2013/10/21/using-the-new-spatial-functions-in-mysql-5-6-for-geo-enabled-applications/
Maybe this helps you http://www.scribd.com/doc/2569355/Geo-Distance-Search-with-MySQL
Basically the problem is that lat/lng are spherical coordinates (lat and lng are angles), and you want to make a search using a linear distance over the spherical surface. Then, you are trying to compare two different things, I mean, angles with kilometers. To do it, you must make a coordinate transformation and then compare.
Hope this simple query helps
SELECT
*
FROM
`locator`
WHERE
SQRT(POW(X(`center`) - 49.843317 , 2) + POW(Y(`center`) - 24.026642, 2)) * 100 < `radius`
details here http://dexxtr.com/post/83498801191/how-to-determine-point-inside-circle-using-mysql
You have to use st_distance_sphere, which will interpret the two points given as geographic points that is lat/lng instead of two points in a two-dimensional coordinate system.
The result is in meters.
mysql> SET #pt1 = ST_GeomFromText('POINT(0 0)');
mysql> SET #pt2 = ST_GeomFromText('POINT(180 0)');
mysql> SELECT ST_Distance_Sphere(#pt1, #pt2);
+--------------------------------+
| ST_Distance_Sphere(#pt1, #pt2) |
+--------------------------------+
| 20015042.813723423 |
The result is in meters.
Here is the documentation:
enter link description here