This may or may not be a simple question.
I have a query which selects all locations within a mile radius around a provided latitude and longitude. That part works perfectly, but I have additional information inside of another table that I would like to match to it. I've tried LEFT JOIN, but it's timing out.
SELECT *,
( 3959 * acos( cos( radians(40.7143528) ) * cos( radians( lat ) )
* cos( radians( lon ) - radians(-74.0059731) ) + sin( radians(40.7143528) )
* sin( radians( lat ) ) ) ) AS distance
FROM locations
LEFT JOIN informations ON
locations.name = informations.name
HAVING distance < 1
Here is what I would like this query to do:
Provide all matching locations within a mile radius (works)
Obtain the name of those stores (works)
Match those names against the names of each store in the "informations" table
Join all of the information in the matching rows together, where "locations.name" and "informations.name" match
The above query seems like it wants to work. I don't get any errors and it shows as valid in any MySQL formatter I use. However, I think I'm making an error somewhere which causes my tiny server to max processor usage.
To a more experienced set of eyes, would you see a reason why this would occur? Other than my server being near useless, of which I'm aware.
Make your initial query a sub-query of the main query, and left join that resulting relation to the new table (with additional information). That should give you performance back
The result will look like this:
SELECT *
FROM(
SELECT *,
( 3959 * acos( cos( radians(40.7143528) ) * cos( radians( lat ) )
* cos( radians( lon ) - radians(-74.0059731) ) + sin( radians(40.7143528) )
* sin( radians( lat ) ) ) ) AS distance
FROM locations
) locations
LEFT JOIN informations
ON location.name =informations.name
The HAVING clause is of course part of query #1.
I use SQL SERVER typically, so the syntax may not be quite right for MYSQL.
Related
I have the following query which does indeed work. It takes in a hard set Latitude and Longitude and finds the closest set of coordinates, along with it's postal code.
What I'm having trouble with is the speed of the query. It's currently taking 3.8 seconds to run and I have 9000 separate coordinates to check.
Any advice on how to speed this up would be greatly appreciated.
SELECT pcds, ROUND(MIN(distance), 4) AS distance FROM
(SELECT `postcode`.`pcds`,(
6371 * acos (
cos ( radians('51.4932392') )
* cos( radians( `postcode`.`lat` ) )
* cos( radians( `postcode`.`lng` ) - radians('-0.0846429') )
+ sin ( radians('51.4932392') )
* sin( radians( `postcode`.`lat` ) )
)
) AS distance
FROM postcode
ORDER BY distance
LIMIT 1
) AS First
What basically i want to do is pick all the coordinates from roadData
one by one and then find all the point in tweetMelbourne within 20
miles of it and insert those point into another table.
So for every (x,y) in roadData table find neighbouring data point from
tweetMelbourne and insert those points into another new table.
So I have to do this:
SELECT geo_coordinates_latitude, geo_coordinates_longitude
FROM tweetmelbourne
HAVING ( 3959 * acos( cos( radians(latitude) ) * cos( radians( geo_coordinates_latitude ) ) *
cos( radians( geo_coordinates_longitude ) - radians(longitude) ) + sin( radians(latitude) ) *
sin( radians( geo_coordinates_latitude ) ) ) ) < .1 ORDER BY distance LIMIT 0 , 20;
in which the value of latitude and longitude i have to get from another table :
select longitude,latitude from roadData;
describe tweetmelbourne;
describe roadData;
SELECT geo_coordinates_latitude, geo_coordinates_longitude
FROM tweetmelbourne;
select longitude,latitude from roadData;
The correct syntax of IN() with multiple arguments is : (Val1,Val2) IN(SELECT VAL1,val2..
SELECT t.address,(t.x+t.y) as z
FROM student t
WHERE (t.x,t.y) IN(SELECT x,y FROM tweet)
Also can be done with a join :
SELECT t.address,(t.x+t.y) as z
FROM student t
JOIN tweet s
ON(t.x = s.x and t.y = s.y)
EDIT: I think what you want is:
SELECT s.address,t.x+t.y as z
FROM student s
CROSS JOIN tweet t
Try this:
SELECT s.address, (t.x + t.y) as z
from (SELECT id,x,y FROM `tweet`) as t, student s
WHERE t.id = s.id;
You need to join the two tables, calculating the distance in the ON clause to select the nearby rows.
SELECT *
FROM tweetmelbourne
JOIN roadData
ON ( 3959 * acos( cos( radians(latitude) ) * cos( radians( geo_coordinates_latitude ) ) *
cos( radians( geo_coordinates_longitude ) - radians(longitude) ) + sin( radians(latitude) ) *
sin( radians( geo_coordinates_latitude ) ) ) ) < .1
This will be very slow if the tables are large. It's not possible to use indexes to implement the join, so it will have to perform that complex formula on every pair of rows. You might want to look at MySQL's Spatial Data extensions.
I have a table of cities with, among other things, population, latitude and longitude. I also have a table of airports with various info including latitude and longitude.
A query like this roughly obtains the population of all towns within 100 km of a given latitude and longitude:
SELECT SUM(cty_population) as cty_population_total FROM
(SELECT
cty_population, (
6371 * acos (
cos ( radians(37.61899948) )
* cos( radians( cty_latitude ) )
* cos( radians( cty_longitude ) - radians(-122.37500000) )
+ sin ( radians(37.61899948) )
* sin( radians( cty_latitude ) )
)
) AS cty_distance
FROM cities
HAVING cty_distance < 100) cty_population_alias
This will give a result like this:
cty_population_total
6541221
In the above query, 37.61899948 is the latitude and -122.37500000 is the longitude.
My question is: can I select an arbitrary number of airports from the airports table, pass their longitudes and latitudes into this subquery in place of the above numbers, and find the city population within 100 km of each airport. Ideally I would have results like this:
airport_name airport_pop
Boston Logan 6654901
London Heathrow 11345690
...etc.
I could do this with scripting, but I am wondering if it can be done with SQL alone? The database engine is MySQL.
You have a very procedural way of thinking this which would not work well in SQL. You can think of it as joining the city with all its nearby airports.
The following may work:
SELECT a.name, SUM(c.cty_population)
FROM cities c JOIN airports a ON (
6371 * acos (
cos ( radians(a.latitude) )
* cos( radians( c.cty_latitude ) )
* cos( radians( c.cty_longitude ) - radians(a.longitude) )
+ sin ( radians(a.latitude) )
* sin( radians( c.cty_latitude ) )
) < 100
WHERE (filter airports or something else here)
GROUP BY a.airport_id, a.name
Also, I suggest you migrate to MySQL 5.7 which includes spatial functions and data types built in.
I'm having a difficult time wrapping my head around how to do this, even with all the searching and reading I've done on this!
I have a query I am using to try to pull all users from a database that have a zip code that falls within a certain distance of a given decimal coordinate. Here's the query that I am running:
select distinct watch_list.username, enabled
from watch_list, registered_users
where watch_list.username = registered_users.username AND watch_list.watchzip = (
SELECT zip,
( 3959 * acos( cos( radians('29.7632800') ) *
cos( radians( lat ) ) *
cos( radians( lng ) -
radians('-95.3632700') ) +
sin( radians('29.7632800') ) *
sin( radians( lat ) ) ) )
AS distance from zip
HAVING distance <= '10');
There error I get back is expected, as my sub query is returning two columns:
MySQL said: Documentation
#1241 - Operand should contain 1 column(s)
How can I do this and filter on the distance without the sub query returning both columns?
P.S. Just for completion and information sake, the "zip" table contains a list of all zip codes in the U.S. along with their decimal coordinates.
Just move the operation out of the column list:
select distinct watch_list.username, enabled
from watch_list, registered_users
where watch_list.username = registered_users.username
AND watch_list.watchzip = (
SELECT zip
from zip
WHERE ( 3959 * acos( cos( radians('29.7632800') ) *
cos( radians( lat ) ) *
cos( radians( lng ) -
radians('-95.3632700') ) +
sin( radians('29.7632800') ) *
sin( radians( lat ) ) ) ) <= '10');
Edit: As P.Salmon mentions, you probably also want to change AND watch_list.watchzip = to AND watch_list.watchzip IN.
I have a table of items and a table of categories. Each item is saved with it co-ordinates, latitude (lat) and longitude (lon), to allow users to search geographically.
When I do a search for items, those which have exactly the same lat and lon as the user, show in one query but not the other.
One query simply selects all items within a category (2), within a range (<1).
SELECT *, c.name as category, c.category_id as CATid,
( 3959 * acos( cos( radians(52.993252) )
* cos( radians( i.latitude ) )
* cos( radians( i.longitude ) - radians(-0.412470) )
+ sin( radians(52.993252) )
* sin( radians( i.latitude ) ) ) ) AS distance
from items i
join categories c on i.category=c.category_id
where i.category=2 group by i.item_id
HAVING distance < 1
order by distance
The other query selects all the categories and counts the number of items within each category, within the specified geographic range (<1)
SELECT *, ( SELECT ( count( 3959 * acos( cos( radians(52.993252) )
* cos( radians( latitude ) )
* cos( radians( longitude )
- radians(-0.412470) )
+ sin( radians(52.993252) )
* sin( radians( latitude ) ) ) )) AS distance
FROM items
WHERE category = category_id
HAVING distance < 2 ) AS howmanyCat,
( SELECT name FROM categories WHERE category_id = c.parent ) AS parname
FROM categories c ORDER BY category_id, parent
Strangely, if you change the search parameter for distance to 2 on the second query it finds it!
Any ideas?
Here is a fiddle to show what I mean
The second query is assigning the count() value as distance.
The first is assigning the arithmetic calculation as distance.
The first is doing what you want, and it is a clearer query.
EDIT:
I also note that the first query is aggregating by item_id. The second is not doing an explicit aggregation in the outer query, but it is choosing all categories. This is another difference between the versions.