I'm storing geo coordinates in a MySQL table using a spatial index. The problem is that queries where I want to know if a tuple/location is within a bounding box (closed polygon described by 5 coordinates; first an last coordinate are the same) return an empty results. Here's a minimum example that is not working for me as expected:
CREATE TABLE osTest(
loc Point NOT NULL
) ENGINE=MyISAM;
CREATE SPATIAL INDEX locIndex ON osTest(loc);
-- New York Central Park, The Great Lawn
INSERT INTO osTest (loc) VALUES (POINT(40.781343, -73.966598));
If I execute the following table scan query:
SELECT AsText(loc), X(loc), Y(loc) FROM osTest;
all seems to work fine -- the result looks like this:
+-----------------------------+-----------+------------+
| AsText(loc) | X(loc) | Y(loc) |
+-----------------------------+-----------+------------+
| POINT(40.781343 -73.966598) | 40.781343 | -73.966598 |
+-----------------------------+-----------+------------+
However, when I try to execute a query that is using the spatial index, the result is always empty. The polygon the in following polygon describes the whole Central Park:
SELECT AsText(loc), X(loc), Y(loc) FROM osTest WHERE WITHIN(loc, GeomFromText('POLYGON(40.800716 -73.958358, 40.796858 -73.949120, 40.764216 -73.973153, 40.768108 -73.981929, 40.800716 -73.958358)') );
I've also tried INTERSECTS, OVERLAPS -- same empty result set. What am I missing here?
I am not an expert on mysql GIS, but in postgis the points have to be Latitude,Longitude. My belief is that it is the same in mysql 5.6 GIS data types as well.
According to that theory; in your query, y and x should be switched
I found the issue. I had an error in my SQL query. It doesn't result in a syntax error, but obviously it doesn't work correctly. More specifically, I had to add additional brackets. I had to change:
GeomFromText('POLYGON(40.800716 -73.958358, ...)')
to
GeomFromText('POLYGON((40.800716 -73.958358, ...))')
I simply overlooked it when I searched for examples. And that I didn't get any syntax errors or something didn't help either.
Related
I am no MySQL expert so no doubt I have overlooked something simple.
I have a MySQL DB (V 5.7.26) and if I run the following query (as an example) on one of my tables I get a result of 39 which is what I expect:
SELECT count(*)
FROM `entities`
WHERE
ST_CONTAINS(
ST_GeomFromText('POLYGON((-0.4120 51.6009, -0.4120 51.3467, 0.1533 51.3467, 0.1533 51.6009, -0.4120 51.6009))', 4326),
gloc
) = 1;
I created the same DB in MySQL V 8.0.23 and did so by exporting table definitions and recreating them by running the queries in the new DB, so as far as I can tell tables definitions etc are identical.
I imported the same data into the new DB and I know the data is correct, for example if I pull a record by another criteria(selecting by record id for example) I can display the record on a map (leaflet) and it is in the correct location.
However if I run the same query as above in my new DB it returns a result of 0.
If I leave out the SRID of 4326 then I get an error (which I would expect) of
/* SQL Error (3033): Binary geometry function st_contains given two geometries of different srids: 0 and 4326, which should have been identical. */
/* Affected rows: 0 Found rows: 0 Warnings: 0 Duration for 0 of 1 query: 0.000 sec. */
So I don't think its an SRID issue.
gloc is defined as type 'geometry', NULL values are allowed though none exist. However if I disallow NULL values and then add a spatial index to gloc column the result is exactly the same.
I would check lat:lon order. MySql 8 follows lat:lon order for 4326 as defined by CRS. Assuming your data is in England, rather than Indian ocean, you should swap coordinate order. Also check other data for same issue.
See also
https://mysqlserverteam.com/axis-order-in-spatial-reference-systems/
I am looking for a solution for finding wether a LAT,LNG Point is contained inside any Polygon in my MySQL table.
For some reason that extends past my SQL knowledge, my queries using ST_Intersects returning 'Function not found'. So i have stried in it's place:
SELECT `area_title` FROM `service_areas` WHERE MBRIntersects(`area_poly`, GEOMFROMTEXT('POINT(40.775032, -73.970778)'));
My table for testing is fairly simply and stores a
1. area_poly GEOMETRY stores POLYGON((-71.740723 41.360319,-71.685791 42.106374,-71.71875 42.407235,-71.905518 42.771211,-72.070312 43.036776,-72.432861 43.157109,-72.718506 43.397065,-73.190918 43.55651,-73.619385 43.580391,-74.32251 43.572432,-75.201416 43.277205,-75.717773 43.004647,-75.926514 42.795401,-76.135254 42.528796,-76.256103 42.138968,-76.289062 41.869561,-76.234131 41.442726,-76.190185 40.955011,-75.992432 40.472024,-75.849609 40.153687,-75.629883 39.783213,-75.311279 39.529467,-74.94873 39.368279,-74.520264 39.257778,-74.256592 39.478606,-71.5979 40.971604,-71.740723 41.360319))
And
2. area_title VARCHAR(20) stores service area 1
I am trying to pass a Point as POINT(40.775032, -73.970778) as shown above.
Expected result would be to return any area_title's that the point is within it's polygon; However, my query returns 0 Rows.
I know there are a ton of questions/answers on slack and the web, but i have not found a solution trying most of the methods. With my lack of SQL knowledge i'm not sure if i'm storing the Poly correctly or not using the correct function to find it.
Any help, even pointing in the right direction is appreciated.
A simple solution for anyone who is running into the same issue:
SELECT ea.name, ea.area_poly from service_areas as ea WHERE contains(ea.area_poly, GeomFromText(AsText(point(#lat, #lng)), 4326))
My polygon ea.area_poly is saved as Polygon((lat1 lng1,lat2 lng2, etc..)) as a geometry type in SQL.
Migrating a MariaDB table with geometric data to MySql, some data cannot be inserted, because they are not well-formed, even if it's not a issue for MariaDB.
This request works on MariaDB (10.2).
CREATE TABLE IF NOT EXISTS geo (
id INT AUTO_INCREMENT NOT NULL,
value GEOMETRY NOT NULL,
SPATIAL INDEX idx_value (value),
PRIMARY KEY(id)
) ENGINE = InnoDB;
INSERT INTO geo (value) SELECT ST_GeomFromText('LINESTRING(1 2)');
Not on MySql (5.7.20), where the error is:
3037 - Invalid GIS data provided to function st_geometryfromtext.
There are three functions to identify such geometries in MySql: ST_IsSimple(), ST_IsValid(), and ST_Validate() but they don't work with badly formatted geometries:
SELECT ST_IsSimple(ST_GeomFromText('LINESTRING(1 2)'));
SELECT ST_IsValid(ST_GeomFromText('LINESTRING(1 2)'));
SELECT ST_AsText(ST_Validate(ST_GeomFromText('LINESTRING(1 1)')));
3055 - Geometry byte string must be little endian.
This example comes from https://dev.mysql.com/doc/refman/5.7/en/spatial-convenience-functions.html, but it doesn't work. So it's strange (the doc was not updated for 5.7). More details about validity on mysql: https://dev.mysql.com/doc/refman/5.7/en/geometry-well-formedness-validity.html (mysql accepts any syntactically well-formed input, but not the geometrically invalid).
Similar issues here:
MySQL spatial geometry validate wkt, where the answer is : the functions provided by MySQL to test validity of geometries requires well formed geometry as input...
MySQL 5.7: Invalid GIS data, where there is the idea to use a stored function and to create an exception handler, so a bit complicated.
A bug report asking for the same issue, but without response: https://bugs.mysql.com/bug.php?id=76595
https://github.com/creof/doctrine2-spatial/issues/155 (doctrine php orm), that says that the result is changing between versions of mysql.
But none of them answer to the issue: how to identify badly formatted geometries on mysql 5.7?
LineString needs at least two Points. Perhaps 5.6 was negligent in pointing that out.
mysql> SELECT hex(ST_GeomFromText('LINESTRING(1 1)'));
ERROR 3037 (22023): Invalid GIS data provided to function st_geometryfromtext.
mysql> SELECT hex(ST_GeomFromText('LINESTRING(1 1, 2 3)'));
+--------------------------------------------------------------------------------------------+
| hex(ST_GeomFromText('LINESTRING(1 1, 2 3)')) |
+--------------------------------------------------------------------------------------------+
| 00000000010200000002000000000000000000F03F000000000000F03F00000000000000400000000000000840 |
+--------------------------------------------------------------------------------------------+
mysql> SELECT ##version;
+-----------+
| ##version |
+-----------+
| 5.7.15 |
+-----------+
I have a data dump (csv) of place names from https://www.ordnancesurvey.co.uk/business-and-government/help-and-support/products/os-open-names.html
I need to import this into mysql however the geometry co-ordinates use BNG (OSGB36). Does Mysql have any functions to convert these co-ordinates to wgs84 lat/long or is there any other sql method to achieve this?
another option is perhaps loading it into postgis - does postgis have any funtion to transform BNG to lat/long? Perhaps I could do that and then export the data once transformed and load it into mysql?
In postgis I could do something as follows (not tested)
select AddGeometryColumn('locations', 'the_geom', 27700, 'POINT', 2);
-- X and Y are the BNG co-ordinates
UPDATE locations SET the_geom = ST_GeomFromText('POINT(' || x || ' ' || y || ')', 27700 );
alter table locations add column lat real;
alter table locations add column long real;
update locations set long=st_x(st_transform(the_geom,4326)),
lat=st_y(st_transform(the_geom,4326));
Is it possible to do these type of function in mysql - basically what are the equivalent functions in mysql. I cant seem to figure the syntax out? The following doesnt work in mysql:
update locations set long=ST_X(ST_Transform(the_geom,4326)),
lat=ST_Y(ST_Transform(the_geom,4326));
I get error function ST_Transform does not exist. I'm using mysql 5.7
* UPDATE *
Sample data:
NAME1 LOCAL_TYPE GEOMETRY_X GEOMETRY_Y DISTRICT_BOROUGH REGION COUNTRY
Southport Town 333510 417225 Sefton North West England
The answer is, of all places, here
Answered by Hartmut Holzgraefe in this comment.
So far the SRID property is just a dummy in MySQL, it is stored as
part of a geometries meta data but all actual calculations ignore it
and calculations are done assuming Euclidean (planar) geometry.
So ST_Transform would not really do anything at this point anyway.
I think the same is still true for MariaDB, at least the knowledge [sic]
base page for the SRID() function still says so:
This WorkLog discusses the progress of implementing ST_Transform.
MySQL 8.0 does seem to have it implemented: https://dev.mysql.com/doc/refman/8.0/en/spatial-operator-functions.html#function_st-transform
So, the solution may require upgrading to MySQL 8.0.
The changelog for the very recent 8.0.13 says:
----- 2018-10-22 8.0.13 General Availability -- -- -----
MySQL now implements the
ST_Transform()
spatial function for use in converting geometry values from one
spatial reference system (SRS) to another. Currently, it supports
conversion between geographic SRSs. For details, see Spatial Operator
Functions.
I tried inserting
PolygonFromText("POLYGON((121.44842136764532 31.22119260287111,
121.45076025390631 31.221990825071376,
121.45402182006842 31.218366658611853,
121.45091045761114 31.217054584347302))")
as a value into a a field of both type Polygon and of type Geometry.
When I run
SELECT PolygonFromText("POLYGON((121.44842136764532 31.22119260287111,
121.45076025390631 31.221990825071376,
121.45402182006842 31.218366658611853,
121.45091045761114 31.217054584347302))")
it returns NULL
My Mysql Version is 5.1.41 - I find the MySql documentation very poor and not user friendly in these cases
I think a Polygon has to close so the last set of coordinates should be same as first one. This will return following
SELECT PolygonFromText("POLYGON((121.44842136764532 31.22119260287111,121.45076025390631 31.221990825071376,121.45402182006842 31.218366658611853,121.45091045761114 31.217054584347302,121.44842136764532 31.22119260287111))");