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;
Related
I am new to sql.
Sample of offerings Table
offering_id | offering_meal_id | offering_name | offering_profile_id | Offering_Expiration_Date_Time | Lat | Lon
Sample of profile Table
profile_id | fullname
I am passing following parameters $latitude , $longitude, $meal_id
I want to write a query which will
get all data from offerings table in basis of latitude and longitude and Offering_Expiration_Date_Time is greater than or equal to today's date. For this I have following calculation which is working.
SELECT *, ( 6371 * ACOS( COS( RADIANS( ".$latitude." ) ) *
COS( RADIANS( Lat ) ) * COS( RADIANS( Lon ) - RADIANS( ".$longitude." ) ) + SIN( RADIANS( ".$latitude." ) )
* SIN( RADIANS( Lat ) ) ) ) AS distance FROM offerings HAVING distance < 3 AND Offering_Expiration_Date_Time>='".date('Y-m-d h:i:s')."'
Next Select only those offering which meal_id = $meal_id
Join profile table and get fullname from it where offerings.offering_profile_id = profile.profile_id
order it by offering_id
EDIT
SELECT offerings.*,profile.fullname,
( 6371 * ACOS( COS( RADIANS( 16.691120 ) ) * COS( RADIANS( Lat ) ) * COS( RADIANS( Lon ) - RADIANS( 74.219978 ) ) + SIN( RADIANS( 16.691120 ) ) * SIN( RADIANS( Lat ) ) ) )
AS distance
FROM offerings
INNER JOIN profile
ON offerings.offering_profille_id = profile.profile_id
WHERE distance < 3
AND offerings.offering_meal_id = 2
AND Offering_Expiration_Date_Time>='2017-08-23 15:43:00'
ORDER BY offerings.offering_id
LIMIT 10
Before your having clause, join to the profile table like so:
Inner join profile on offerings.offering_profile_id = profile.profile_id
Then include at end:
Order by offerings.offering_id
Also make sure to include in your select statement
Profile.fullname
Also change having to where and add this into your where condition:
And offerings.offering_meal_id = $meal_id
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
I have two sql queries which when run independent produces the correct results
Query 1
SELECT id,
(6371 * acos( cos( radians(9.977364864079215) ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians(76.58620953448485) ) + sin( radians(9.977364864079215) ) * sin( radians( latitude ) ) ) )
AS distance
FROM geodata HAVING distance < 20
ORDER BY distance
LIMIT 0 , 20;
Query 2
SELECT DISTINCT e.* FROM schools e
WHERE (
(e.type = 'preprimary')
)
AND(
e.title LIKE '%government%'
)
LIMIT 0, 10
I want to merge the first query with the second one, so that it should return all "preprimary" type schools with title like "government" located within 20KM radius and the result needs to be ordered by the distance.
How can I merge the two queries? I tried using JOINING the geodata table on the school table. But I dont know the remaining. Sorry, if this is a silly question. I am pretty new to SQL world.
SELECT DISTINCT school.* FROM
( SELECT geodata.id,
(6371 * acos( cos( radians(9.977364864079215) ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians(76.58620953448485) ) + sin( radians(9.977364864079215) ) * sin( radians( latitude ) ) ) )
AS distance ,school.*
FROM geodata LEFT JOIN school on geodata.id=school.id
WHERE
(school.type = 'preprimary')
AND(
school.title LIKE '%government%'
)
AND school.id IS NOT NULL
HAVING distance < 20 )x
ORDER BY x.distance
LIMIT 0 , 10;
Try this:
SELECT *
From (
SELECT DISTINCT e.* ,
(6371 * acos( cos( radians(9.977364864079215) ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians(76.58620953448485) ) + sin( radians(9.977364864079215) ) * sin( radians( latitude ) ) )
) as distance
FROM schools e
LEFT JOIN geodata g ON e.id=g.id
WHERE (e.type = 'preprimary')
AND ( e.title LIKE '%government%' )
) as s
Where s.distance < 20
Order by s.distance
I have 2 select statements:
timestamp of emp getting awards for specific emp id
SELECT * FROM user_table,employeetable,awards where user_table.empid=employeetable.empid AND user_table.empid=awards.empid AND user_table.empid=123 ORDER BY timestamp DESC
All employees staying around 25 miles from the current loc:current location: lat =37 lng=-122
SELECT * ( 3959 * acos( cos( radians(37) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(-122) )+ sin( radians(37) ) * sin( radians( lat ) ) ) ) AS distance FROM user_table,employeetable,awards where user_table.empid=employeetable.empid AND user_table.empid=awards.empid HAVING distance < 25 ORDER BY distance;
How do I combine both and ORDER BY timestamp ?btw both have field timestamp.
1.has specific user
2.all users within specific radius
I really appreciate any help.Thanks in Advance.
You can combine the two queries into a single query, just using logic in the where clause (which this has turned into a having clause:
select *, ( 3959 * acos( cos( radians(37) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(-122) )+ sin( radians(37) ) * sin( radians( lat ) ) ) ) as distance
from user u join
employee e
on u.empid = e.empid join
awards a
on u.empid = a.empid
having empid = 123 or distance < 25;
This uses having instead of where so the distance column alias can be used instead of the formula.
I have a charities table with fields: charity, postcode
and a postcodes table with fields: postcode, lat, lng
I want to POST a postcode from a web page and find the nearest charities
I'm something of a mysql beginner so I'm a bit lost, but I've been trying various ideas with joins and sub queries none of which work (I either get syntax errors or 'Operand should contain 1 column' with variations on the code below) I've got
Select charity,postcode,
(
(Select lat as lat2, lng as lng2
from postcodes
where postcode='WN8'
)
3959 * acos( cos( radians(lat2) ) * cos( radians( lat ) ) *
cos( radians( lng ) - radians(lng2) ) +
sin( radians(lat2) ) * sin( radians( lat ) ) )
)
AS distance
FROM postcodes
JOIN Charities on charities.postcode=postcodes.postcode
HAVING distance < 30 ORDER BY distance LIMIT 0 , 30;
I've seen lots of examples on here where lat2 and lng2 are obtained from posted values but not from a table in the db.
p.s 'where postcode='WN8' in the example is just for testing
Not sure what error you are getting with the above SQL.
However try this minor tweak and let us know what errors you get
SELECT charity, postcode,
(3959 * acos( cos( radians(CustPostcode.lat) ) * cos( radians( postcodes.lat ) ) *
cos( radians( postcodes.lng ) - radians(CustPostcode.lng) ) +
sin( radians(CustPostcode.lat) ) * sin( radians( postcodes.lat ) ) )
) AS distance
FROM postcodes
INNER JOIN Charities ON charities.postcode=postcodes.postcode
CROSS JOIN (SELECT lat, lng FROM postcodes WHERE postcode='WN8') CustPostcode
HAVING distance < 30
ORDER BY distance
LIMIT 0 , 30;
If you want to know the nearest 30 postcodes and the distances from each charity then something like this would do the job (not tested so excuse any typos).
SELECT charity, Charities.postcode, Postcodes.postcode, PostcodeDistance.distance
FROM Charities
CROSS JOIN Postcodes
INNER JOIN (SELECT PC1.postcode AS postcode1, PC2.postcode AS postcode2, (3959 * acos( cos( radians(PC1.lat) ) * cos( radians( PC2.lat ) ) *
cos( radians( PC2.lng ) - radians(PC1.lng) ) +
sin( radians(PC1.lat) ) * sin( radians( PC2.lat ) ) )
) AS distance
FROM postcodes PC1
CROSS JOIN postcodes PC2) PostcodeDistance
ON Charities.postcode = PostcodeDistance.postcode1
AND Postcodes.postcode = PostcodeDistance.postcode2
HAVING distance < 30
ORDER BY distance
LIMIT 0 , 30;
This should find you the charities within 30 miles
SELECT charity, Charities.postcode, PostcodeDistance.distance
FROM Charities
INNER JOIN (
SELECT PC2.postcode AS postcode2, (3959 * acos( cos( radians(PC1.lat) ) * cos( radians( PC2.lat ) ) *
cos( radians( PC2.lng ) - radians(PC1.lng) ) +
sin( radians(PC1.lat) ) * sin( radians( PC2.lat ) ) )
) AS distance
FROM postcodes PC1
CROSS JOIN postcodes PC2
WHERE PC1.postcode='WN8'
) PostcodeDistance
ON Charities.postcode = PostcodeDistance.postcode2
WHERE PostcodeDistance.distance < 30
ORDER BY PostcodeDistance.distance
LIMIT 0 , 30;