SQL - Unqiue results based on criteria - mysql

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!

Related

How to use Haversine formula in Sequelize-typescript to get distance between two coordinates

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_table.SOME_COLUMN ORDER BY distance ASC"
I want to convert this query in sequelize-typescript.

Select one field from query with subquery

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

Having issue with Having Query in MySQL

I'm trying to do this query:
SELECT *, ( 6371 * acos( cos( radians(43.656906) ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians(-79.434356) ) + sin( radians(43.656906) ) * sin( radians( latitude ) ) ) ) AS distance FROM Locations HAVING distance < 10 AND HAVING category='%Family%'
But I get this error:
#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use
near 'HAVING category='%Family%' LIMIT 0, 30' at line 1
Does anybody know what is the problem?
I hope category is column in your table
SELECT *, ( 6371 * acos( cos( radians(43.656906) ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians(-79.434356) ) + sin( radians(43.656906) ) * sin( radians( latitude ) ) ) ) AS distance FROM Locations where category like '%Family%' HAVING distance < 10
You can not add having conditions twice .You can use "AND" inside the "Having" condition.So the code will be :
SELECT *, ( 6371 * acos( cos( radians(43.656906) ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians(-79.434356) ) + sin( radians(43.656906) ) * sin( radians( latitude ) ) ) ) AS distance FROM Locations HAVING distance < 10 AND category='%Family%'
You need to remove the second HAVING and just use AND to tell MySQL that both conditions must hold.
SELECT *, ( 6371 * acos( cos( radians(43.656906) ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians(-79.434356) ) + sin( radians(43.656906) ) * sin( radians( latitude ) ) ) ) AS distance FROM Locations HAVING distance < 10 AND category='%Family%'

SQL with Multiple Where Clauses

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.

MySQL - Ordered GROUP BY Issue Optimization

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