I have a table which has some users in it. They all have a username, latitude,longitude and some other fields.
I want to select all users within 5KM range of a given coordinate and based on some other criteria. Now this part was not hard.
However, I also want the SQL statement to return users with given usernames independently from the other criterias mentioned above.
So, basically, the SQL should return users based on the distance and other criterias AND users who have a specific username despite if they match the criterias or no.
Here is what I have, but it does not work:
SELECT idUser
, username
, telephone
, latitude
, longitude
, ( 6371 * acos( cos( radians(?) ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians(?) ) + sin( radians(?) ) * sin( radians( latitude ) ) ) ) AS distance
FROM main
WHERE active = ?
AND idUser != ?
HAVING distance < 5
OR username = mike
OR username = john
You can add the condition to the having clause:
SELECT idUser, username, telephone, latitude, longitude,
( 6371 * acos( cos( radians(?) ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians(?) ) + sin( radians(?) ) * sin( radians( latitude ) ) ) ) AS distance
FROM main
WHERE active = ? AND idUser != ?
HAVING distance < 5 OR username IN ('mike', 'john');
You may need to remove the idUser . . . I'm not sure if that is related to username or not.
EDIT:
If you want to guarantee that mike and john are in the result set, you can do:
(SELECT idUser, username, telephone, latitude, longitude,
( 6371 * acos( cos( radians(?) ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians(?) ) + sin( radians(?) ) * sin( radians( latitude ) ) ) ) AS distance
FROM main
WHERE active = ? AND idUser != ? AND username NOT IN ('mike', 'john')
HAVING distance < 5
)
UNION ALL
(SELECT idUser, username, telephone, latitude, longitude,
( 6371 * acos( cos( radians(?) ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians(?) ) + sin( radians(?) ) * sin( radians( latitude ) ) ) ) AS distance
FROM main
WHERE username IN ('mike', 'john')
)
Or:
SELECT idUser, username, telephone, latitude, longitude,
( 6371 * acos( cos( radians(?) ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians(?) ) + sin( radians(?) ) * sin( radians( latitude ) ) ) ) AS distance
FROM main
WHERE (active = ? AND idUser <> ?) OR username IN ('mike', 'john')
HAVING distance < 5 OR username IN ('mike', 'john');
Or move all conditions to the HAVING clause:
SELECT idUser, username, telephone, latitude, longitude,
( 6371 * acos( cos( radians(?) ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians(?) ) + sin( radians(?) ) * sin( radians( latitude ) ) ) ) AS distance
FROM main
WHERE (active = ? AND idUser <> ?) OR username IN ('mike', 'john')
HAVING (active = ? AND idUser <> ? AND distance < 5) OR
username IN ('mike', 'john');
Related
Making a dealer locator where people search for a dealer near them. I want it to work in such a way that if a dealer has multiple branches near the person, only the closest branch shows. So the "name" field should be unique in the results with the result shown having the least distance to the person searching versus other rows that have the same "name" field. I also want only the closest 5 dealers shown ordered by their dealer level, or medal. Right now I have the following:
$query = sprintf("SELECT
name, address, contact, image, medal, phone, email, website, lat, lng,
( 3959 * acos( cos( radians('%s') ) * cos( radians( lat ) ) * cos( radians( lng ) - radians('%s') ) + sin( radians('%s') ) * sin( radians( lat ) ) ) ) AS distance
FROM dealers
HAVING distance < 60
ORDER BY medal, distance
LIMIT 0 , 5",
mysql_real_escape_string($center_lat),
mysql_real_escape_string($center_lng),
mysql_real_escape_string($center_lat),
mysql_real_escape_string($radius));
$result = mysql_query($query);
From what I've read, it sounds like I need to do something like:
SELECT * FROM (
SELECT ROW_NUMBER() OVER (PARTITION BY name ORDER BY distance) AS num
FROM dealers)a
WHERE a.num = 1
Or something like that, but I can't get it to work right. Any insights on how I can get this to function would be greatly appreciated.
Get the minimum distance per dealer and of these take the first five. Then select again from the table in order to get complete records, but take only those records already identified by dealer and distance.
A WITH clause would be helpful, but MySQL doesn't support it. Well, ...
SELECT
name, address, contact, image, medal, phone, email, website, lat, lng,
( 3959 * acos( cos( radians('%s') ) * cos( radians( lat ) ) * cos( radians( lng ) - radians('%s') ) + sin( radians('%s') ) * sin( radians( lat ) ) ) ) AS distance
FROM dealers
WHERE (name, ( 3959 * acos( cos( radians('%s') ) * cos( radians( lat ) ) * cos( radians( lng ) - radians('%s') ) + sin( radians('%s') ) * sin( radians( lat ) ) ) )) IN
(
SELECT
name, min( 3959 * acos( cos( radians('%s') ) * cos( radians( lat ) ) * cos( radians( lng ) - radians('%s') ) + sin( radians('%s') ) * sin( radians( lat ) ) ) ) AS distance
FROM dealers
GROUP BY name
HAVING distance < 60
ORDER BY distance
LIMIT 5
)
ORDER BY distance, medal;
Final Solution was:
SELECT name, address, contact, image, medal, phone, email, website, lat, lng,
( 3959 * acos( cos( radians('%s') ) * cos( radians( lat ) ) * cos( radians( lng ) - radians('%s') ) + sin( radians('%s') ) * sin( radians( lat ) ) ) ) AS distance
FROM dealers
WHERE (name,
( 3959 * acos( cos( radians('%s') ) * cos( radians( lat ) ) * cos( radians( lng ) - radians('%s') ) + sin( radians('%s') ) * sin( radians( lat ) ) ) ) )
IN
(SELECT name, distance
FROM (SELECT name,
MIN( 3959 * acos( cos( radians('%s') ) * cos( radians( lat ) ) * cos( radians( lng ) - radians('%s') ) + sin( radians('%s') ) * sin( radians( lat ) ) ) ) AS distance
FROM dealers
WHERE (3959 * acos( cos( radians('%s') ) * cos( radians( lat ) ) * cos( radians( lng ) - radians('%s') ) + sin( radians('%s') ) * sin( radians( lat ) ) ) ) < 90
GROUP BY name)
t)
ORDER BY medal, distance
LIMIT 0, 5",
mysql_real_escape_string($center_lat),
mysql_real_escape_string($center_lng),
mysql_real_escape_string($center_lat),
mysql_real_escape_string($center_lat),
mysql_real_escape_string($center_lng),
mysql_real_escape_string($center_lat),
mysql_real_escape_string($center_lat),
mysql_real_escape_string($center_lng),
mysql_real_escape_string($center_lat),
mysql_real_escape_string($center_lat),
mysql_real_escape_string($center_lng),
mysql_real_escape_string($center_lat)
Thank you Thorsten Kettner, for putting me on the right track!
I am using the MySQL query to find distance between tow zip-codes when lat long is given.
SELECT postcode, ( 3959 * acos( cos( radians( 52.47592 ) ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians( -1.90539 ) ) + sin( radians( 52.47592 ) ) * sin( radians( latitude ) ) ) ) AS distance FROM ukpostcodes HAVING distance <= 5 ORDER BY distance
it is working fine. But I want only postcode in result. I don't want distance column in result .
How can I achieve it.
Thanks
SELECT postcode FROM(
SELECT postcode, ( 3959 * acos( cos( radians( 52.47592 ) ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians( -1.90539 ) ) + sin( radians( 52.47592 ) ) * sin( radians( latitude ) ) ) ) AS distance FROM ukpostcodes HAVING distance <= 5 ORDER BY distance
) AS tbl
I have a table of items which each have latitude and longitude values to allow me to calculate distances.
I'm trying the following but it returns: Unknown column distance in where clause:
select ( 3959 * acos( cos( radians('53.993252') )
* cos( radians( latitude ) )
* cos( radians( longitude )
- radians('-0.432470') )
+ sin( radians('53.993252') )
* sin( radians( latitude ) ) ) ) AS distance from items where distance < 1000
select ( 3959 * acos( cos( radians('53.993252') )
* cos( radians( latitude ) )
* cos( radians( longitude )
- radians('-0.432470') )
+ sin( radians('53.993252') )
* sin( radians( latitude ) ) ) ) AS distance from items having distance < 1000
WHERE doesnt see aliases use HAVING.
You can use subquery -
SELECT * FROM (
SELECT
(3959 * ACOS(COS(RADIANS('53.993252')) * COS(RADIANS(latitude)) * COS(RADIANS(longitude) - RADIANS('-0.432470')) + SIN(RADIANS('53.993252')) * SIN(RADIANS(latitude)))) AS distance
FROM items)t
WHERE distance < 1000;
First -- I have read about 7 pages of posts with similar titles but couldn't find the right insight for my challenge
My SQL:
SELECT name, address, lat, lng, city, state, phone, zip, info
, ( 3959 * acos( cos( radians('37.4969') ) * cos( radians( lat ) ) * cos( radians( lng ) - radians('-122.2674') ) + sin( radians('37.4969') ) * sin( radians( lat ) ) ) ) AS distance
FROM myhealthfinder_map
HAVING distance < '50' and location = '2'
ORDER BY distance LIMIT 0 , 10
I get the error message: Invalid query: Unknown column 'location' in 'having clause'
if instead of HAVING I just make it WHERE location = '2' then it works fine [it finds the column] (but I need the distance selector).
Any suggestion on how to knock this down?
Use both WHERE and HAVING. HAVING is used for aggregated and calculated columns. And WHERE on plain old columns.
SELECT name, address, lat, lng, city, state, phone, zip, info
, ( 3959 * acos( cos( radians('37.4969') ) * cos( radians( lat ) ) * cos( radians( lng ) - radians('-122.2674') ) + sin( radians('37.4969') ) * sin( radians( lat ) ) ) ) AS distance
FROM myhealthfinder_map
WHERE location = '2'
HAVING distance < '50'
ORDER BY distance LIMIT 0 , 10
More explanation found here WHERE vs HAVING
Don't use HAVING without GROUP BY. You can try this instead
SELECT name, address, lat, lng, city, state, phone, zip, info, ( 3959 * acos( cos( radians('37.4969') ) * cos( radians( lat ) ) * cos( radians( lng ) - radians('-122.2674') ) + sin( radians('37.4969') ) * sin( radians( lat ) ) ) ) AS distance
FROM myhealthfinder_map
WHERE location = '2' AND
( 3959 * acos( cos( radians('37.4969') ) * cos( radians( lat ) ) * cos( radians( lng ) - radians('-122.2674') ) + sin( radians('37.4969') ) * sin( radians( lat ) ) ) ) < 50
ORDER BY distance LIMIT 0 , 10
It's not pretty, but it should work.
I have a table called stores which contains store information and more importantly location coordinates of stores of various merchants. A merchant can have multiple stores at various locations. I need a listing of stores ordered by distance (from a particular location) with only the closest store of each merchant showing in the list.
The following query works but I believe its sub-optimal. Is there a way to revise or improve this query?
SELECT
`Store`.`id`,
`Merchants`.`id`,
`Store`.`area_id`,
`Store`.`url`,
( 6371 * acos( cos( radians(18.973212066666665) ) * cos( radians( Store.latitude ) ) * cos( radians( Store.longitude ) - radians(72.8140959) ) + sin( radians(18.973212066666665) ) * sin( radians( Store.latitude ) ) ) ) AS distance
FROM
`stores` AS `Store`
INNER JOIN
(SELECT DISTINCT id,( 6371 * acos( cos( radians(18.973212066666665) ) * cos( radians( Store.latitude ) ) * cos( radians( Store.longitude ) - radians(72.8140959) ) + sin( radians(18.973212066666665) ) * sin( radians( Store.latitude ) ) ) ) AS distance FROM stores as Store WHERE Store.active=1 AND Store.parent_id=0 AND (( 6371 * acos( cos( radians(18.973212066666665) ) * cos( radians( Store.latitude ) ) * cos( radians( Store.longitude ) - radians(72.8140959) ) + sin( radians(18.973212066666665) ) * sin( radians( Store.latitude ) ) ) ) < 50) GROUP BY Store.id ORDER BY distance) AS `St` ON (`St`.`id` = `Store`.`id`)
INNER JOIN
merchants AS `Merchants` ON (`Store`.`merchant_id` = `Merchants`.`id`)
WHERE
(( 6371 * acos( cos( radians(18.973212066666665) ) * cos( radians( `Store`.`latitude` ) ) * cos( radians( `Store`.`longitude` ) - radians(72.8140959) ) + sin( radians(18.973212066666665) ) * sin( radians( `Store`.`latitude` ) ) ) ) < 50) AND
`Store`.`parent_id` = 0 AND
`Store`.`active` = 1
GROUP BY
`Merchants`.`id`
ORDER BY
`distance` ASC
LIMIT 10
I am using the following formula to calculate distance ( 6371 * acos( cos( radians(LATITUDE) ) * cos( radians( Store.latitude ) ) * cos( radians( Store.longitude ) - radians(LONGITUDE) ) + sin( radians(LATITUDE) ) * sin( radians( Store.latitude ) ) ) )
Looks like you don't need the merchant table at all. You are using it only for merchant_id which you have in the store table anyways. So you can avoid this join.
If I understand what you need correctly, you can try this query:
select id, merchant_id, area_id, url,
min(distance function you are using) as distance
from stores group by merchant id, order by distance
I did not actually run it, but the idea should work.
-Mansi