0

I have a database which contains postcodes along with their geo coordinates. The data looks similar to the following

 id | Postcode   | Longitude  |  Latitude      |  
-------------------------------------------------
 1  | W12 7GF    | 51.51527   |  -0.08816      |  
-------------------------------------------------
 2  | SW16 6GF   | 51.51528   |  -0.15960      |  
-------------------------------------------------
 3  | W1 4FT     | 51.51528   |  -0.11590      | 
-------------------------------------------------

What I first do is take in a postcode (I have hardcoded it for now).

$sql = "SELECT * FROM postcodes WHERE `postcode` = 'W14 6TY'";

Once I execute this, I get the Longitude and Latitude for that postcode. I also set a couple more variables.

$lat1 = $row['Latitude'];
$lon1 = $row['Longitude'];
$d = 5;
$r = 3959;

Now what I do is get all other postcodes within a 5 mile radius of the above postcode. To do this, I do

$latN = rad2deg(asin(sin(deg2rad($lat1)) * cos($d / $r) + cos(deg2rad($lat1)) * sin($d / $r) * cos(deg2rad(0))));
$latS = rad2deg(asin(sin(deg2rad($lat1)) * cos($d / $r) + cos(deg2rad($lat1)) * sin($d / $r) * cos(deg2rad(180))));
$lonE = rad2deg(deg2rad($lon1) + atan2(sin(deg2rad(90)) * sin($d / $r) * cos(deg2rad($lat1)), cos($d / $r) - sin(deg2rad($lat1)) * sin(deg2rad($latN))));
$lonW = rad2deg(deg2rad($lon1) + atan2(sin(deg2rad(270)) * sin($d / $r) * cos(deg2rad($lat1)), cos($d / $r) - sin(deg2rad($lat1)) * sin(deg2rad($latN))));

$query = "SELECT * FROM postcodes WHERE (Latitude <= $latN AND Latitude >= $latS AND Longitude <= $lonE AND Longitude >= $lonW) AND (Latitude != $lat1 AND Longitude != $lon1)  ORDER BY Latitude, Longitude ASC LIMIT 30";
$result2 = $conn->query($query);

As you can see I limit the results because I do not want hundreds returned. Lastly, I output the data

echo "<div class='container'>";
    echo "<div class='row'>";
        echo "<div class='col-md-12 col-sm-12 col-xs-12'>";
            echo "<table class=\"table table-striped\">";
                echo "<tr><th>Postcode</th><th>Latitude</th><th>Longitude</th><th>Miles, Point A To B</th></tr>\n";
                    while ($row = $result2->fetch_assoc()) {
                        echo "<tr><td>$row[Postcode]</td><td>$row[Latitude]</td><td>$row[Longitude]</td>";
                        echo "<td>".acos(sin(deg2rad($lat1)) * sin(deg2rad($row['Latitude'])) + cos(deg2rad($lat1)) * cos(deg2rad($row['Latitude'])) * cos(deg2rad($row['Longitude']) - deg2rad($lon1))) * $r."</td>";
                        echo "</tr>\n";
                    }
                echo "</table>\n<br />\n";
        echo "</div>";
    echo "</div>";
echo "</div>";

As you can see in the output, I also calculate the Miles, Point A To B. I cant do this at a database query level because I need to do all that maths on the resulting geo-coordinates.

At the moment, the data is ordered by Latitude and Longitude. Because these numbers do not make much sense, the output looks a bit funny.

My question is, would it be possible to order the output based on the smallest to highest number of miles between points? I presume I would need to remove the limit (so it can work on all outputs), but not sure if I can do this because I do not calculate this until after the query.

Any advice appreciated.

Thanks

6
  • Use usort with a comparison function that calculates the distances and compare them. Commented Oct 19, 2015 at 21:38
  • 1
    scribd.com/doc/2569355/Geo-Distance-Search-with-MySQL might help you. Commented Oct 19, 2015 at 21:40
  • 1
    Yes, you can. Check Sorting MySQL query by Latitude/Longitude Commented Oct 19, 2015 at 21:41
  • usort, array_map, stored procedures, etc. There are many many functions that you can use or you can even write your own. Do a google search. Frankly I'm surprised as to the fact that there is a new question on sorting on SO. Heck, just write a simple bubble sort on your array. Commented Oct 19, 2015 at 21:42
  • Possible duplicate of PHP Sorting Commented Oct 19, 2015 at 21:43

1 Answer 1

2

E.g.

DROP TABLE IF EXISTS my_table;

CREATE TABLE my_table
(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,Postcode VARCHAR(12) NOT NULL
,Longitude DECIMAL(8,5)
,Latitude DECIMAL(8,5) NOT NULL
);

INSERT INTO my_table VALUES
(1  ,'W12 7GF',51.51527,-0.08816),
(2  ,'SW16 6GF',51.51528,-0.15960),
(3  ,'W1 4FT',51.51528,-0.11590),
(4  ,'W14 8UX',51.49645,-0.20975);

SELECT y.*
     , ROUND(geo_distance_km(x.latitude,x.longitude,y.latitude,y.longitude),2) dist 
  FROM my_table x 
  JOIN my_table y 
    ON y.id <> x.id 
 WHERE x.postcode = 'W14 8UX';
+----+----------+-----------+----------+-------+
| id | Postcode | Longitude | Latitude | dist  |
+----+----------+-----------+----------+-------+
|  1 | W12 7GF  |  51.51527 | -0.08816 | 13.69 |
|  2 | SW16 6GF |  51.51528 | -0.15960 |  5.96 |
|  3 | W1 4FT   |  51.51528 | -0.11590 | 10.65 |
+----+----------+-----------+----------+-------+

Obviously, I've left a crucial bit out of this answer. I wonder if you can figure that bit out for yourself.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.