Mysql find Point in polygon. - mysql

i want to Select ID from table Locations where a point ( 25.10785 55.18114 ) exists in a polygon that.
I tried everything possible , while it returns null for everything.
Polygon((25.11031 55.18408,25.11109 55.18459,25.11288 55.18811,25.11653 55.19301,25.12197 55.20176, 25.1034 55.23103, 25.09471 55.24247, 25.0826 55.24944, 25.05652 55.24897, 25.05526 55.23672, 25.05306 55.22412, 25.06665 55.22071, 25.07212 55.21617, 25.07821 55.20957, 25.09016 55.19002, 25.09583 55.18403, 25.1046 55.17734, 25.10785 55.18114,25.11031 55.18408))
this is how the polygon looks like.
I want mysql to return ID if a point exists in the polygon

Have a look at the mysql functions Containt or ST_Contains. ST_Contains(g1, g2) returns 1 or 0 to indicate whether g1 completely contains g2.
In your example you could do something like:
SELECT id FROM your_table WHERE CONTAINS(your_polygon, PointFromText(POINT(25.10785 55.18114))
Make sure to check what mysql version you are using.

Related

MySQL Check Point Within a polygon stored within a table

A little out of my depth with this one.
I've ran the query:
SELECT ST_Contains(
PolygonFromText('
POLYGON((
60.930551 -0.775212,
60.332866 -0.417906,
59.935582 -0.887788,
59.837354 -1.156991,
58.919848 -2.577975,
58.378359 -2.935748,
57.934035 -3.75355,
57.761068 -3.563538,
57.859628 -1.643417,
57.538993 -1.423404,
56.382748 -2.522191,
55.846937 -1.945553,
55.618743 -2.262236,
55.463878 -2.131039,
55.42282 -2.162707,
54.968355 -3.03811,
54.960564 -3.232644,
54.929382 -3.449798,
54.540197 -4.141976,
54.467094 -5.149036,
55.657203 -6.713395,
56.947221 -7.700598,
57.681709 -7.656722,
58.298006 -7.239903,
60.930551 -0.775212))'),
PointFromText("POINT(57.05 -4.49)"));
Which returns a 1 to confirm that 57.05, -4.49 is indeed within the polygon.
I want to store the polygon data in my database and did so with:
INSERT INTO polygons (`ownerID`, `polygon`)
VALUES ("test", PolygonFromText('POLYGON((60.930551 -0.775212, 60.332866 -0.417906, 59.935582 -0.887788, 59.837354 -1.156991, 58.919848 -2.577975, 58.378359 -2.935748, 57.934035 -3.75355, 57.761068 -3.563538, 57.859628 -1.643417, 57.538993 -1.423404, 56.382748 -2.522191, 55.846937 -1.945553, 55.618743 -2.262236, 55.463878 -2.131039, 55.42282 -2.162707, 54.968355 -3.03811, 54.960564 -3.232644, 54.929382 -3.449798, 54.540197 -4.141976, 54.467094 -5.149036, 55.657203 -6.713395, 56.947221 -7.700598, 57.681709 -7.656722, 58.298006 -7.239903, 60.930551 -0.775212))')");
But I am now struggling to run the initial ST_Contains query whilst also returning the polygon from the table.
SELECT #Test := polygon FROM polygons where ownerID = 'test';
SELECT ST_CONTAINS(ST_GEOMFROMTEXT(#Test), PointFromText("POINT(57.05, -4.499)"));
Returns a null response and I'm sure there is a simple way to do this but unfortunately it evades my basic skills and googling has returned lots of examples where the polygon is defined in the query, but not where it is stored in a table.
How can I check to see if a point is within a polygon that is stored in the table polygons?
Thanks
When storing the value to your variable #Test you forgot to select the geom value as text and your POINT has a comma in it.
SELECT #Test := ST_AsText(`polygon`) FROM `polygons` WHERE ownerID = 'test';
SELECT ST_CONTAINS(ST_GEOMFROMTEXT(#Test), ST_PointFromText("POINT(57.05 -4.499)"));
Or without converting to WKT -
SELECT #Test := `polygon` FROM `polygons` WHERE ownerID = 'test';
SELECT ST_CONTAINS(#Test, ST_PointFromText("POINT(57.05 -4.499)"));
Or just -
SELECT *,
ST_AsText(`polygon`),
ST_CONTAINS(`polygon`, ST_GeomFromText("POINT(57.05 -4.499)"))
FROM `polygons`
WHERE `owner_id` = 'test';

Mysql function MBRContains is not accurate

I have the following POLYGON (in the image you can see the area it covers)
POLYGON((-74.05100448502202 4.7239278424321,-74.05092938316898 4.7241416902206,-74.04830618275201 4.7237460717602,-74.04643668306903 4.7234306460692,-74.04635688735101 4.7234105978214,-74.04636526925401 4.7233310730989,-74.046191260944 4.72327293317,-74.04579027069599 4.7232007594583,-74.04141290558402 4.7214258184083,-74.03746201170497 4.7197791822891,-74.03565688503801 4.7189879401666,-74.033484295736 4.7180897723398,-74.03098447693401 4.7170526009038,-74.028731840457 4.7161167561787,-74.02852820211899 4.7150714370973,-74.026398371001 4.6877232674918,-74.02558060109601 4.6874859863574,-74.02454587610401 4.686797564651,-74.024665108676 4.6863189291555,-74.025470986757 4.6857975214267,-74.02585246812498 4.6846813784365,-74.02580479605103 4.6834369175226,-74.01962984798399 4.684922743491,-74.028472839649 4.6765444849623,-74.032273278366 4.6775012677607,-74.03825980124901 4.6799297676049,-74.048215993474 4.6850422042295,-74.05718496514402 4.6867981911917,-74.05100448502202 4.7239278424321))
When I execute MBRIntersect, MBRContains and Within functions they return that the green marker is inside of the polygon, but it is not (as you can see in the image). I'm executing the next sentence to get that:
SET #g1 = ST_GeomFromText('POLYGON((-74.05100448502202 4.7239278424321,-74.05092938316898 4.7241416902206,-74.04830618275201 4.7237460717602,-74.04643668306903 4.7234306460692,-74.04635688735101 4.7234105978214,-74.04636526925401 4.7233310730989,-74.046191260944 4.72327293317,-74.04579027069599 4.7232007594583,-74.04141290558402 4.7214258184083,-74.03746201170497 4.7197791822891,-74.03565688503801 4.7189879401666,-74.033484295736 4.7180897723398,-74.03098447693401 4.7170526009038,-74.028731840457 4.7161167561787,-74.02852820211899 4.7150714370973,-74.026398371001 4.6877232674918,-74.02558060109601 4.6874859863574,-74.02454587610401 4.686797564651,-74.024665108676 4.6863189291555,-74.025470986757 4.6857975214267,-74.02585246812498 4.6846813784365,-74.02580479605103 4.6834369175226,-74.01962984798399 4.684922743491,-74.028472839649 4.6765444849623,-74.032273278366 4.6775012677607,-74.03825980124901 4.6799297676049,-74.048215993474 4.6850422042295,-74.05718496514402 4.6867981911917,-74.05100448502202 4.7239278424321))', 4326);
SELECT MBRContains(#g1, ST_PointFromText('POINT(-74.051585 4.680108)', 4326)) g1,
st_distance(ST_PointFromText('POINT(-74.051585 4.680108)', 4326), #g1) distance
and I'm getting
g1 distance
1 | 0.005489581062607619
But I was expecting
g1 distance
0 | 0.005489581062607619
I have try the following cases:
Save geometry assigning 4326 SRID.
Using other functions, getting same response.
I'm Using 5.7.14 MySQL version
What am I doing wrong?
I worked around this issue just validating that there's no distance. But, why am I getting this result from that functions?
I don't have a MySQL to play with right now. So i first try to duplicate your query in a SQL Server Spatial.
DECLARE #g1 geometry
DECLARE #h1 geometry
SET #g1= geometry::STGeomFromText('POLYGON((-74.05100448502202 4.7239278424321,-74.05092938316898 4.7241416902206,-74.04830618275201 4.7237460717602,-74.04643668306903 4.7234306460692,-74.04635688735101 4.7234105978214,-74.04636526925401 4.7233310730989,-74.046191260944 4.72327293317,-74.04579027069599 4.7232007594583,-74.04141290558402 4.7214258184083,-74.03746201170497 4.7197791822891,-74.03565688503801 4.7189879401666,-74.033484295736 4.7180897723398,-74.03098447693401 4.7170526009038,-74.028731840457 4.7161167561787,-74.02852820211899 4.7150714370973,-74.026398371001 4.6877232674918,-74.02558060109601 4.6874859863574,-74.02454587610401 4.686797564651,-74.024665108676 4.6863189291555,-74.025470986757 4.6857975214267,-74.02585246812498 4.6846813784365,-74.02580479605103 4.6834369175226,-74.01962984798399 4.684922743491,-74.028472839649 4.6765444849623,-74.032273278366 4.6775012677607,-74.03825980124901 4.6799297676049,-74.048215993474 4.6850422042295,-74.05718496514402 4.6867981911917,-74.05100448502202 4.7239278424321))', 4326);
SET #h1 = geometry::STGeomFromText('POINT(-74.051585 4.680108)', 4326)
SELECT #g1.STContains(#h1) contain, #g1.STDistance(#h1) distance
And the result is what you may expect:
contain distance
0 | 0.005489581062607675
Here is the reason behind this:
I am using STContains not MBRContains based on your description of what you are looking for. MBRContains function first create a Minimal Bounding Rectangle over your polygon, and use that new polygon feature do the contain judegement. In your example, the point does fall into the MBR of your polygon so thats why your MySQL result is not what you expect. And STContains is the right function you are looking for.
Official reference: Mysql spatial Link

How to insert the polygon and checking if a passed polygon is inside it in mysql database?

Can I check if a polygon is inside another polygon in mysql query? What will be the query to get all the polygons which contains the passed polygon in the where string?
After googling, I found a query:-
SELECT *, AsText(poly) FROM geos
WHERE Contains(
GeomFromText('POLYGON((42.000497 -109.050149,
41.002380 -102.051881,
39.993237 -102.041959,
38.999037 -109.045220,
42.000497 -109.050149))'), poly );
I am not sure what it is doing basically? So what will the query to insert the polygon and checking if a passed polygon is inside it?
Thanks all in advance!
You can insert a polygon like this:
SET #g1 = 'POLYGON ((
//your points of polygon here
))';
INSERT INTO geos set poly=ST_GeomFromText(#g1);
And if you want to check another g2 if it contains g1:
SELECT * FROM geos WHERE ST_CONTAINS(ST_GeomFromText(#g2), poly);

Mysql 5.1 spatial overlaps why doesn't work properly?

I'm doing some test with spatial operations on MySQL 5.1 and I've found some problems overlaping a mutlipolygon with a polygon.
Test set
1) Multipolygon: Are 2 polygons on it, one represents continental France and other one Corsica
2) Polygon. Just a rectangle.
3) Multipolygon and polygon, doesn't overlap. Testesd with JTS test builder
4) MySQL returns that overlaps.
I'm doing something wrong? Do you know wether overlaping it considers the multipolygon bounding box instead of the multipolygon borders (looks like it is this case).
Thanks in advance,
Xavi
Here the test query:
SELECT overlaps(
GeomFromText('MULTIPOLYGON(
((
-1.5719044 45.66331767,
-1.66445017 44.15596196,
-2.09633041 43.35382557,
-1.44851005 42.79046377,
0.98852813 42.40442147,
2.16077434 42.15335565,
3.57980926 42.24476801,
3.36386913 42.9035504,
4.13508385 43.24156757,
6.44872768 42.69984551,
8.00528012 44.22125179,
7.43172878 44.63085344,
7.47952458 45.30714395,
6.9537692 46.70140581,
8.10087187 47.70798437,
8.19646379 48.47416978,
8.67442321 49.16649286,
5.42429902 49.94163752,
4.75515576 50.46172136,
2.07858291 51.36572924,
1.1226639 50.82543226,
0.59690852 50.21768192,
-0.69358204 49.6640024,
-1.98407259 50.06452024,
-2.55762393 49.5090723,
-1.93627663 48.9472454,
-2.55762393 48.88442555,
-3.99150219 49.16649286,
-5.37758466 48.60075831,
-5.42538062 47.90060118,
-4.03929815 47.41771923,
-2.84439951 46.96299696,
-2.03186838 46.2405562,
-1.5719044 45.66331767,
-1.5719044 45.66331767
)),
((
7.03485087 43.06152362,
8.23794566 42.56366976,
8.19646379 41.73912551,
8.67442321 41.09395768,
9.86932185 41.20193051,
9.86932185 42.72995934,
9.1523828 43.49754453,
8.23794566 42.56366976,
7.03485087 43.06152362,
7.03485087 43.06152362
))
)
')
,
GeomFromText('POLYGON((
1.1578032214844 40.974486726133,
1.1578032214844 41.79873497231,
3.1820341785157 41.79873497231,
3.1820341785157 40.974486726133,
1.1578032214844 40.974486726133
))')
)
Overlaps and MBROverlaps are the same function on MysQL 5.1. I missed this comment on the documentation :
Note
Currently, MySQL does not implement these functions according to the specification. Those that are implemented return the same result as the corresponding MBR-based functions.
Seems that from MySQL 5.6 onwards mysql will support Overlaps on polygons, ST_Overlaps.

MySQL - Perl: How to get array of zip codes within submitted "x" miles of submitted "zipcode" in Perl example

I have found many calculations here and some php examples and most are just over my head.
I found this example:
SELECT b.zip_code, b.state,
(3956 * (2 * ASIN(SQRT(
POWER(SIN(((a.lat-b.lat)*0.017453293)/2),2) +
COS(a.lat*0.017453293) *
COS(b.lat*0.017453293) *
POWER(SIN(((a.lng-b.lng)*0.017453293)/2),2))))) AS distance
FROM zips a, zips b
WHERE
a.zip_code = '90210' ## I would use the users submitted value
GROUP BY distance
having distance <= 5; ## I would use the users submitted value
But, I am having trouble understanding how to implement the query with my database.
It looks like that query has all I need.
However, I cannot even find/understand what b.zip_code actually is! (whats the b. and zips a, zips b?)
I also do not need the state in the query.
My mySQL db structure is like this:
ZIP | LAT | LONG
33416 | 26.6654 | -80.0929
I wrote this in attempt to return some kind of results (not based on above query) but, it only kicks out one zip code.
## Just for a test BUT, in reality I desire to SELECT a zip code WHERE ZIP = the users submitted zip code
## not by a submitted lat lon. I left off the $connect var, assume it's there.
my $set1 = (26.6654 - 0.20);
my $set2 = (26.6654 + 0.20);
my $set3 = (-80.0929 - 0.143);
my $set4 = (-80.0929 + 0.143);
my $test123 = $connect->prepare(qq{SELECT `ZIP` FROM `POSTAL`
WHERE `LAT` >= ? AND `LAT` <= ?
AND `LONG` >= ? AND `LONG` <= ?}) or die "$DBI::errstr";
$test123->execute("$set1","$set2","$set3","$set4") or die "$DBI::errstr";
my $cntr;
while(#zip = $test123->fetchrow_array()) {
print qq~$zip[$cntr]~;
push(#zips,$zip[$cntr]);
$cntr++;
}
As you can see, I am quite the novice so, I need some hand holding here with verbose explanation.
So, in Perl, how can I push zip codes into an array from a USER SUBMITTED ZIP CODE and user submitted DISTANCE in miles. Can be a square instead of a circle, not really that critical of a feature. Faster is better.
I'll tackle the small but crucial part of the question:
However, I cannot even find/understand what b.zip_code actually is! (whats the "b." and "zips a, zips b"?)
Basically, the query joins two tables. BUT, both tables being joined are in fact the same table - "zips" (in other words, it joins "zips" table to itself"). Of course, since the rest of the query needs to understand when you are referring to the first copy of the "zips" table and when to the second copy of the "zips" table, you are giving a table alias to each copy - to wit, "a" and "b"'.
So, "b.xxx" means "column xxx from table zips, from the SECOND instance of that table being joined".
I don't see what's wrong with your first query. You have latitude and longitude in your database (if I'm understanding, you're comparing a single entry to all others). You don't need to submit or return the state that's just part of the example. Make the first query work like this:
my $query = "SELECT b.zip_code,
(3956 * (2 * ASIN(SQRT(
POWER(SIN(((a.lat-b.lat)*0.017453293)/2),2) +
COS(a.lat*0.017453293) *
COS(b.lat*0.017453293) *
POWER(SIN(((a.lng-b.lng)*0.017453293)/2),2))))) AS distance
FROM zips a, zips b WHERE
a.zip_code = ?
GROUP BY distance having distance <= ?";
my $sth = $dbh->prepare($query);
$sth->execute( $user_submitted_zip, $user_submitted_distance );
while( my ($zip, $distance) = $sth->fetchrow() ) ) {
# do something
}
This won't be that fast, but if you have a small record set ( less than 30k rows ) it should be fine. If you really want to go faster you should look into a search engine such as Sphinx which will do this for you.
fetchrow_array returns a list of list references, essentially a two-dimensional array, where each row represents a different result from the database query and each column represents a field from the query (in your case, there is only one field, or column, per row).
Calling while ($test123->fetchrow_array()) will cause an infinite loop as your program executes the query over and over again. If the query returns results, then the while condition will be satisfied and the loop will repeat. The usual idiom would be to say something more like for my $row ($test123->fetchrow_array()) { ..., which will only execute the query once and then iterate over the results.
Each result is a list reference, and the zip code you are interested in is in the first (and only) column, so you could accumulate the results in an array like this:
my #zips = (); # for final results
for my $row ($test123->fetchrow_array()) {
push #zips, $row->[0];
}
or even more concisely with Perl's map statement:
my #zips = map { $_->[0] } $test123->fetchrow_array()
which does the same thing.