MySQL - Find points within radius from database - mysql

I have a table which has a POINT column containing the latitude and longitude of various locations.
I then also have a users location from geo-location in the browser.
What I need to be able to do is find all records from the table where the POINT value in the is within a 10 km radius (or X km radius), ordered by distance with the closest first.
My table has a SPATIAL index on the POINT column.

I'm currently working on a project where I'm calculating distances between multiple locations. I'm using the following query for selecting object_id's which are within a given radius.
SELECT id,
( 6371 *
ACOS(
COS( RADIANS( db_latitude ) ) *
COS( RADIANS( $user_latitude ) ) *
COS( RADIANS( $user_longitude ) -
RADIANS( db_longitude ) ) +
SIN( RADIANS( db_latitude ) ) *
SIN( RADIANS( $user_latitude) )
)
)
AS distance FROM the_table HAVING distance <= $the_radius ORDER BY distance ASC"
I can't explain the ACOS formula itself because I got it from research.
db_latitude = database latitude field
db_longitude = database longitude field
$user_latitude = browser latitude coördinate
$user_longitude = browser longitude coördinate
$the_radius = the radius that you want to search in
This is in kilometers.

The query below actually worked for me :
$query = "SELECT *,
( 6371 *
acos(
cos( radians( ".$user_lat." ) ) *
cos( radians( lat ) ) *
cos( radians( lng ) -
radians( ".$user_lng." ) ) +
sin( radians( ".$user_lat." ) ) *
sin( radians( lat ) ) ) )
AS distance FROM parkings
HAVING distance <= ".$radius." ORDER BY distance ASC";
$stmt = $conn->execute($query);
$rows = $stmt->fetchAll('assoc');
where:
$user_lat and $user_lng is browser's lat and lng,
$radius = 10,
table name is parkings

May be this help for you,
https://ru.scribd.com/presentation/2569355/Geo-Distance-Search-with-MySQL
For Django I use this
dist = 20 #дистанция 20 км
mylon = 51.5289156201 # долгота центра
mylat = 46.0209384922 # широта
lon1 = mylon-dist/abs(math.cos(math.radians(mylat))*111.0) # 1 градус широты = 111 км
lon2 = mylon+dist/abs(math.cos(math.radians(mylat))*111.0)
lat1 = mylat-(dist/111.0)
lat2 = mylat+(dist/111.0)
profiles = UserProfile.objects.filter(lat__range=(lat1, lat2)).filter(lon__range=(lon1, lon2))
It search all users in squar 20km.

Related

Longitude latitude query but only rows that match column in same table

I've looked and looked and tried and tried with no success. I have a query that I use to display users within a certain distance range. It works great, but it returns all users from my users table, and I want it to only return users where the value in account_type is equal to '1'. So basically different kinds of account types share my users table and on this page I only want one type of user to be display. I've tried all sorts of things, including joining the same table which I know makes no sense and it didn't work anyway. Basically, I would like to know where in this query I can add a 'WHERE' clause to check the column named 'account_type'.
Here's my functional query:
SELECT `user_id`, ( 3959 * acos( cos( radians('".$lat."') ) * cos( radians( lat ) ) * cos( radians( lng ) - radians('".$lng."') ) + sin( radians('".$lat."') ) * sin( radians( lat ) ) ) ) AS distance FROM users HAVING distance <= '".$dist."' ORDER BY distance
Since I only want to return users from that table that have account_type = 1, I tried doing many different variations of the following, with no success:
SELECT `user_id`, `account_type`, ( 3959 * acos( cos( radians('".$lat."') ) * cos( radians( lat ) ) * cos( radians( lng ) - radians('".$lng."') ) + sin( radians('".$lat."') ) * sin( radians( lat ) ) ) ) AS distance FROM users ***WHERE `account_type` = '1'*** HAVING distance <= '".$dist."' ORDER BY distance
SELECT `user_id`, `account_type`, ( 3959 * acos( cos( radians('".$lat."') ) * cos( radians( lat ) ) * cos( radians( lng ) - radians('".$lng."') ) + sin( radians('".$lat."') ) * sin( radians( lat ) ) ) ) AS distance FROM users HAVING distance <= '".$dist."' ***WHERE `account_type` = '1'*** ORDER BY distance
any many others though I won't pollute this topic any further. Can someone please tell me what I'm doing wrong? Thank you
#rhavendc was correct. I'm a moron. The account that I created to test this I used some far away location and though there are more than 20 test accounts on my site, there were none within 100miles of the crazy location my test account was using as far as those matching account_type='1'
So once I realized that it took 2 seconds to just use this query to get the proper result
$qry="SELECT user_id, ( 3959 * acos( cos( radians('".$lat."') ) * cos( radians( lat ) ) * cos( radians( lng ) - radians('".$lng."') ) + sin( radians('".$lat."') ) * sin( radians( lat ) ) ) ) AS distance FROM users WHERE account_type = '1' HAVING distance <= '".$dist."' ORDER BY distance";
Thanks for everyone's input. I apologize for my stupidity.

Virtual column unknown when comparing lat lng

I am attempting to return only rows where the latitude and longitude being passed into the query, when compared to the latitude and longitude stored in the database, is a certain amount of miles apart.
The query is as follows:
SELECT
c.google_theatre_id
AS cinema_id,
c.name
AS cinema_name,
( 3959 * acos( cos( radians('50.4521013') ) *
cos( radians( latitude ) ) *
cos( radians( longitude ) -
radians('-3.5247389') ) +
sin( radians('50.4521013') ) *
sin( radians( latitude ) ) ) )
AS distance
FROM
google_cinemas c, app_users u
WHERE
distance < u.range
AND
u.id = 126
ORDER BY
distance
The query is designed to get the distance and then compare it to a column (range) in the app_users table.
When running the query, I'm getting an error of distance being an unknown column.
As this is a virtual column, is there a different way of comparing?
Thanks :)
you need to use HAVING instead of WHERE.. think of it this way WHERE is when you make an order at a restraunt and HAVING is picking stuff off of the plate when it comes to your table... you cannot reference an alias before the plate comes to your table only after it has been built
SELECT
c.google_theatre_id AS cinema_id,
c.name AS cinema_name,
( 3959 * acos( cos( radians('50.4521013') ) *
cos( radians( latitude ) ) *
cos( radians( longitude ) -
radians('-3.5247389') ) +
sin( radians('50.4521013') ) *
sin( radians( latitude ) ) )
) AS distance
FROM google_cinemas c, app_users u
WHERE u.id = 126
HAVING distance < u.range
ORDER BY distance
alternatively you can use it as a sub query which could be faster since HAVING re-evaluates the entire query.
SELECT *
FROM
( SELECT
c.google_theatre_id AS cinema_id,
c.name AS cinema_name,
( 3959 * acos( cos( radians('50.4521013') ) *
cos( radians( latitude ) ) *
cos( radians( longitude ) -
radians('-3.5247389') ) +
sin( radians('50.4521013') ) *
sin( radians( latitude ) ) )
) AS distance,
u.range
FROM google_cinemas c, app_users u
WHERE u.id = 126
ORDER BY distance
)t
WHERE distance < range

Combining multiple where conditions in mysql SELECT query

So here's my issue:
I have a database table where I have latitudes and longitudes and a timestamp. I need to be able to search through this table using PHP. What would the query be to find rows with lats and lons in a certain range, and, on top of this, in a certain time frame.
I have found two separate queries that would work while browsing through the internet, but I can't find a clear way to combine multiple conditions.
The two queries are:
SELECT id, ( 3959 * acos( cos( radians(37) ) * cos( radians( lat ) ) *
cos( radians( lng ) - radians(-122) ) + sin( radians(37) ) *
sin( radians( lat ) ) ) ) AS distance
FROM markers
HAVING distance < 25
ORDER BY distance
LIMIT 0 , 20;
enter code here
SELECT * FROM `table` WHERE `date_field` BETWEEN 'date1' AND 'date2'
I need to find top twenty results where timestamp and lat and long are in range.
Thanks!
EDIT: All fields are in the same table.
If all data is in the same table, you can do:
SELECT id, ( 3959 * acos( cos( radians(37) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(-122) ) + sin( radians(37) ) * sin( radians( lat ) ) ) ) AS distance
FROM markers
WHERE date_field BETWEEN 'date1' AND 'date2'
HAVING distance < 25
ORDER BY distance
LIMIT 0 , 20;

Two the same subqueries in query - how to make them 1?

I have table places
place_id | city | country_code | zipcode | lat | lon
Now I want to show places that are within 25 miles of place A. Place A has place_id 1.
SELECT *
FROM `places`
WHERE ( 3959 * acos( cos( radians((SELECT lat FROM places WHERE place_id=1)) ) * cos( radians( lat ) ) * cos( radians( lon ) - radians((SELECT lon FROM places WHERE place_id=1)) ) + sin( radians((SELECT lat FROM places WHERE place_id=1)) ) * sin( radians( lat ) ) ) ) < 25;
This works ok, but there are two the same subqueries
SELECT lat FROM places WHERE place_id=1
Is it possible to optimize this query to not have two the same subqueries but make them into 1?
Your three subqueries will execute for every row in the outer table.
What you can do is convert those subqueries to a single JOIN which will only execute once for the entire query in order to find the latitude and longitude of place_id 1:
SELECT a.*
FROM places a
JOIN (SELECT lat, lon FROM places WHERE place_id = 1) b ON
(3959 * acos( cos( radians(b.lat) ) * cos( radians( a.lat ) ) * cos( radians( a.lon ) - radians(b.lon) ) + sin( radians(b.lat) ) * sin( radians( a.lat ) ) ) ) < 25;
Derive a new table from the subquery and make join with the original table, like
SELECT *
FROM places p, (SELECT lat AS new_lat FROM places WHERE place_id = 1) l
WHERE blah blah
now you can replace the subquery with column 'new_lat'.
You can use variable #var_lon to cache output of query as:
SELECT *
FROM `places`
WHERE ( 3959 * acos( cos( radians((SELECT lat FROM places WHERE place_id=1)) ) * cos( radians( lat ) ) * cos( radians( lon ) - radians((SELECT #var_lon := lon FROM places WHERE place_id=1)) ) + sin( radians(#var_lon) ) * sin( radians( lat ) ) ) ) < 25;

SQL location from a known point query

I have a MySQL database with the following table
int - id
float 2,6 - long
float 2,6 - lat
int - radius
I want to create a SQL query which returns the ID & Distance from a given location(long & lat)
I found the following piece of code which works:
SELECT id, ( 3959 * acos( cos( radians(37) ) * cos( radians( lat ) ) *
cos( radians( lng ) - radians(-122) ) + sin( radians(37) ) *
sin( radians( lat ) ) ) ) AS distance FROM markers
HAVING distance < 25 ORDER BY distance LIMIT 0 , 20;
I want to alter this query to return only the rows where the computed length is smaller the radius (a column i my table)
replacing the 25 with the radius doesn't work.
Is there a way to achieve that without using two SQL queries ?
problem is occured because the result distance is in float and radius is an integer datatype so you need to CAST radius as float. try below
SELECT id, ( 3959 * acos( cos( radians(37) ) * cos( radians( lat ) ) *
cos( radians( lng ) - radians(-122) ) + sin( radians(37) ) *
sin( radians( lat ) ) ) ) AS distance FROM markers
HAVING distance < CAST (radius AS float) ORDER BY distance LIMIT 0 , 20;
HAPPY TO HELP :)