I\'m using MySQL Spatial Extensions to store data about roads and hotels. I store the hotel data as a Point while I store the road data as LineString. The tables look like this<
I have been also working on this issue, but unfortunately finding the nearest road for Hotels is an unfavorable solution. I have found that the entrance the road is on is the definitive answer. In other words the address. This means having an address table and matching points to nearest address road.
This was a very useful answer for me, but I'm using MySQL 5.7.18, which has more advanced or just different geo query functions. The distance function posted isn't needed anymore- use ST_Distance_Sphere. So here's an update of the same code to make DistanceFromLine compliant with modern (5.7.6+) MySQL...
DROP function IF EXISTS `DistanceFromLine`;
delimiter //
CREATE FUNCTION `DistanceFromLine`(
route LINESTRING, point1 POINT
) RETURNS INT DETERMINISTIC
BEGIN
DECLARE a INT Default 0 ;
DECLARE minDistance INT Default 0;
DECLARE currentDistance INT Default 0;
DECLARE currentpoint point ;
DECLARE size INT Default 0 ;
SET size = ST_NumPoints(route);
simple_loop: LOOP
SET a = a+1;
SET currentpoint = ST_PointN(route,a);
SET currentDistance = ST_Distance_Sphere(point1,currentpoint);
IF a = 1 THEN
SET minDistance = currentDistance;
END IF;
IF currentDistance < minDistance THEN
SET minDistance = currentDistance;
END IF;
IF a=size THEN
LEAVE simple_loop;
END IF;
END LOOP simple_loop;
RETURN (minDistance);
END//
You can create two functions in the database:
Compare the distance between your point and lines and choose the shortest one.
Here is the Distance function
delimiter //
CREATE FUNCTION distance (latA double, lonA double, latB double, LonB double)
RETURNS double DETERMINISTIC
BEGIN
SET @RlatA = radians(latA);
SET @RlonA = radians(lonA);
SET @RlatB = radians(latB);
SET @RlonB = radians(LonB);
SET @deltaLat = @RlatA - @RlatB;
SET @deltaLon = @RlonA - @RlonB;
SET @d = SIN(@deltaLat/2) * SIN(@deltaLat/2) +
COS(@RlatA) * COS(@RlatB) * SIN(@deltaLon/2)*SIN(@deltaLon/2);
RETURN 2 * ASIN(SQRT(@d)) * 637101;
END//
Here is DistanceFromLine function:
DROP function IF EXISTS `DistanceFromLine`;
delimiter //
CREATE FUNCTION `DistanceFromLine`(
route LINESTRING, point1 POINT
) RETURNS INT DETERMINISTIC
BEGIN
DECLARE a INT Default 0 ;
DECLARE minDistance INT Default 0;
DECLARE currentDistance INT Default 0;
DECLARE currentpoint point ;
DECLARE size INT Default 0 ;
SET size = NumPoints(route);
simple_loop: LOOP
SET a = a+1;
SET currentpoint = PointN(route,a);
SET currentDistance = Distance(X(point1), Y(point1),
X(currentpoint),Y(currentpoint));
IF a = 1 THEN
SET minDistance = currentDistance;
END IF;
IF currentDistance < minDistance THEN
SET minDistance = currentDistance;
END IF;
IF a=size THEN
LEAVE simple_loop;
END IF;
END LOOP simple_loop;
RETURN (minDistance);
END//