I am pretty new to SQL queries.
I have a google SQL Search example
SELECT cID,
(6371 * acos
(
cos(radians(51.455643))
* cos(radians(latCord))
* cos(radians(longCord) - radians(7.011555))
+ sin(radians(51.455643))
* sin(radians(latCord))
)
) AS distance
FROM breitengrade
HAVING distance < 50
ORDER BY distance
LIMIT 0, 20
and a own SQL query
SELECT breitengrade.cID
,breitengrade.latCord
,breitengrade.longCord
,Pages.cIsActive
FROM breitengrade
INNER JOIN Pages ON breitengrade.cID = Pages.cID
WHERE cIsActive = '1'
How can I combine these 2 queries into one so that I can get one single result set?
SELECT breitengrade.cID,
breitengrade.latCord,
breitengrade.longCord,
Pages.cIsActive
(6371 * acos
(
cos(radians(51.455643))
* cos(radians(latCord))
* cos(radians(longCord) - radians(7.011555))
+ sin(radians(51.455643))
* sin(radians(latCord))
)
) AS distance
FROM breitengrade
INNER JOIN Pages ON breitengrade.cID = Pages.cID
WHERE cIsActive = '1'
HAVING distance < 50
ORDER BY distance
LIMIT 0, 20
Related
I have the following query, that selects places withing given radius:
SELECT *
FROM (
SELECT
group,
name,
111.1111 *
DEGREES(ACOS(LEAST(1.0, COS(RADIANS(".$lat."))
* COS(RADIANS(t1.lat))
* COS(RADIANS(".$lon.") - RADIANS(t1.lon))
+ SIN(RADIANS(".$lat."))
* SIN(RADIANS(t1.lat))))) AS distance
FROM t1
) AS grp
WHERE distance < 10
Is there a way to count how many locations in each group withing this query?
In MySQL you can use HAVING to reduce the number of rows.
SELECT
`group`, COUNT(*) NumOfNames
FROM
(SELECT
`group`,
name,
ST_DISTANCE_SPHERE(POINT('.$lon.', '.$lat.'), POINT(t1.lon, t1.lat)) / 1000 AS distance
FROM
t1
HAVING distance < 10) t2
GROUP BY `group`
I need to take out values from database , based on distance from any given point and then order by distance ascending. Longitude and latitudes are saved in database as float field. Here is my query
SELECT
*,
#distance : = 6371 * 2 * asin(sqrt(POW(sin(({lat} - radians(address.latitude)) / 2), 2) + cos({lat}) * cos(radians(address.latitude)) * POW(sin(({lon} - radians(address.longitude)) / 2), 2)))
FROM
service,
provider,
address
WHERE
service.provider_id = provider.id
AND provider.address_id = address.id
AND provider.status = True
AND
(
6371 * 2 * asin(sqrt(POW(sin(({lat} - radians(address.latitude)) / 2), 2) + cos({lat}) * cos(radians(address.latitude)) * POW(sin(({lon} - radians(address.longitude)) / 2), 2)))
)
< 10
order by
#distance
I need to reuse the distance for condition like where #distance < 10
but I'm unable to reuse, it returns empty list. whereas #distance in ORDER BY is working fine. How can i reuse variable in where clause ?
Assuming you do not need #DISTANCE outside the select, here's an approach to try:
SELECT *,
6371 * 2 * asin(sqrt(POW(sin(({lat} - radians(address.latitude)) / 2), 2) + cos({lat}) * cos(radians(address.latitude)) * POW(sin(({lon} - radians(address.longitude)) / 2), 2))) AS DISTANCE
FROM service,
provider,
address
WHERE
service.provider_id = provider.id
AND provider.address_id = address.id
AND provider.status = True
HAVING
DISTANCE < 10
ORDER BY
DISTANCE
Note that a I have given the calculation an alias DISTANCE(see far right of select) and used HAVING rather than WHERE for the reference to the alias.
Avoid using MySQL variables; they are obsolete in newer versions of MySQL. Also, it's better to use modern syntax join (SQL-92) instead of old joins.
Anyway, I think the following query produces what you want:
select *
from (
SELECT
*,
6371 * 2 * asin(sqrt(POW(sin(({lat} - radians(a.latitude)) / 2), 2)
+ cos({lat}) * cos(radians(a.latitude)) * POW(sin(({lon}
- radians(a.longitude)) / 2), 2))) as distance
FROM service s
JOIN provider p ON s.provider_id = p.id
JOIN address a ON p.address_id = a.id
WHERE p.status = True
) x
WHERE distance < 10
ORDER BY distance
So I'm having a problem when I add in ORDER BY date_last_access DESC the whole query slows down to 3secs and without it's about 0.2secs, why is it running so slow and how can I change the query to run faster?
There are also indexes on all the tables and fields used.
Users: 1+ million records
Likes: 5+ million records (over 1 billion in production)
Tables will be growing really fast once in production.
QUERY
SELECT
id,
sid,
first_name,
date_birth,
location,
date_created,
date_last_access,
(3956 * 2 * ASIN(
SQRT(
POWER(
SIN(
({LAT} - latitude) * pi() / 180 / 2
),
2
) + COS({LAT} * pi() / 180) * COS(latitude * pi() / 180) * POWER(
SIN(
({LON} - longitude) * pi() / 180 / 2
),
2
)
)
)) AS distance
FROM
users
WHERE
`id` != {UID} AND
`gender` = {GEND} AND
`date_birth` BETWEEN {DOB_MIN} AND {DOB_MAX} AND
`status` = 'active' AND
(SELECT COUNT(*) FROM likes WHERE likes.judged_user = users.id AND likes.user_id = {UID}) = 0
HAVING distance <= {DIST}
ORDER BY date_last_access DESC
LIMIT {ROWS}
EXPLAIN
1 PRIMARY users ref PRIMARY,Index_2,discovery,index_1 index_1 2 const 226184 Using index condition; Using where; Using filesort
2 DEPENDENT SUBQUERY likes eq_ref PRIMARY,index_1,index_2 PRIMARY 16 const,hello.users.id 1 Using index
INDEXES
LIKES - user_id, judged_user - NORMAL - BTREE
USERS - id, gender, date_birth, status, date_last_access - NORMAL - BTREE
When I order by id instead of date_last_access it seems to run much faster, could it be cause date_last_access is a datetime format?
First try run a EXPLAIN of your query. This will show you what fields and operations are slowing your query. Then try to make joins with indexed columns and filter you resultset with more specific values.
Simplyfying the subquery could be a better way to avoid extra processing time (COUNT):
(SELECT COUNT(*) FROM likes WHERE likes.judged_user = users.id AND likes.user_id = {UID}) = 0
could change to
(SELECT 1 FROM likes WHERE likes.judged_user = users.id AND likes.user_id = {UID} limit 1) IS NULL
Avoiding a subquery could be the best way to improve the performance of the query. You could check what options could be better for your case (an index for likes.user_id is required in this case)
FROM
users
LEFT JOIN (
SELECT distinct judged_user FROM likes WHERE likes.user_id = {UID}
) l ON l.judged_user=users.id
WHERE
`id` != {UID} AND
`gender` = {GEND} AND
`date_birth` BETWEEN {DOB_MIN} AND {DOB_MAX} AND
`status` = 'active' AND
l.judged_user is NULL
You should phrase the FROM clause as:
WHERE `id` <> {UID} AND
`gender` = {GEND} AND
`date_birth` BETWEEN {DOB_MIN} AND {DOB_MAX} AND
`status` = 'active' AND
NOT EXISTS (SELECT 1 FROM likes l WHERE l.judged_user = users.id AND l.user_id = {UID})
HAVING distance <= {DIST}
For this query, you can try two indexes:
LIKES(judged_user, user_id)
USERS(Gender, status, date_birth, id)
For the result on my page I need to order the results by distance. The page gets the current position of the user and retrieves the closest 30 results of that position.
Next to the order of the distance I also want to order the results for every venue by price.
Problem is that the price order works, but not the distance order. I can't figure out how my function is ordering the results because there is no structure in it (sometimes the closest result is on the last placing, sometimes it is in the middle, sometimes in the beginning, it's really weird).
My SQL statement looks like that:
$lat = '48.213688';
$lng = '16.408229';
$sql = "SELECT *, (3959 * acos(cos(radians('".$lat."')) * cos(radians(venue_address_lat)) * cos(radians(venue_address_lng) - radians('".$lng."')) + sin(radians('".$lat."')) * sin(radians(venue_address_lat)))) AS distance
FROM car_offer JOIN venues_infos ON car_offer.venues_infos_id = venues_infos.venue_id WHERE (3959 * acos(cos(radians('".$lat."')) * cos(radians(venue_address_lat)) * cos(radians(venue_address_lng) - radians('".$lng."')) + sin(radians('".$lat."')) * sin(radians(venue_address_lat)))) < 1.5
AND car_offer.offer_date = CURDATE()
AND venue_address_postcode = 1020
OR car_offer.offer_date = '0000-00-00'
ORDER BY distance, offer_price_small LIMIT 0,30";
The lat, lng in the database is from Google Maps, so this should be accurate.
I think you are better of using a outer query in this case and then do the order by in outer query like below. (OR) you can use the same distance calculation expression in your order by. Notice I have moved the distance < 1.5 from inner to outer query. Moreover, I am in doubt whether you can use distance in your order by clause like the way you are using (mean in the same query level unless it's from a derived table expression) since distance is a column alias.
SELECT * FROM
(
SELECT *, (3959 * acos(cos(radians('".$lat."')) * cos(radians(venue_address_lat)) * cos(radians(venue_address_lng) - radians('".$lng."')) + sin(radians('".$lat."')) * sin(radians(venue_address_lat)))) AS distance
FROM car_offer
JOIN venues_infos
ON car_offer.venues_infos_id = venues_infos.venue_id
WHERE car_offer.offer_date = CURDATE()
AND venue_address_postcode = 1020
OR car_offer.offer_date = '0000-00-00'
) tab
WHERE distance < 1.5
ORDER BY distance, offer_price_small
LIMIT 0,30
Schema:
place(pid, name, type, lat, lng, deleted)
I want to select count of places, grouping them by their type and
having a distance of < 10 KM from a particular lat, lng
Query:
SELECT count(p.type) as count
FROM (place as p)
where p.deleted != 1
and p.pid in
(
select p2.pid,
IFNULL(acos(sin((18.5236 *pi()/180)) * sin((p2.lat*pi()/180))+cos((18.5236 *pi()/180)) * cos((p2.lat *pi()/180)) * cos(((73.8478 - p2.lng)*pi()/180))) * 6371.009, 0) AS distance
from place p2
having `distance` < 10
)
group by p.type;
Error:
Operand should contain 1 column(s)
That is because I am selecting 2 columns i.e pid and distance in the sub select query. But without using a 2nd select column how can I calculate the distance.
Rewrite your script like this
SELECT count(p.type) AS count,
-- remove this if not necessary
SUM(IFNULL(acos(sin((18.5236 *pi()/180)) * sin((p.lat*pi()/180))+cos((18.5236 *pi()/180)) * cos((p.lat *pi()/180)) * cos(((73.8478 - p.lng)*pi()/180))) * 6371.009, 0)) AS distance
FROM place AS p
WHERE p.deleted != 1
GROUP BY p.type
HAVING SUM(IFNULL(acos(sin((18.5236 *pi()/180)) * sin((p.lat*pi()/180))+cos((18.5236 *pi()/180)) * cos((p.lat *pi()/180)) * cos(((73.8478 - p.lng)*pi()/180))) * 6371.009, 0)) < 10