I have a query which returns map markers within a radius (in miles) of a given position (lat/lng). My query works when reading the data, but I am wanting to set up pagination so need to count the records first to determine how many pages of data I will have.
My query is :
SET #LAT := 53.068464;
SET #LNG := -4.076113;
SET #Miles := 10;
SELECT (3959 * acos( cos( radians(#LAT) ) * cos( radians( M.Lat ) ) * cos(
radians( M.Lng ) - radians(#LNG) ) + sin( radians(#LAT) ) * sin( radians(
M.Lat ) ) ) ) AS distance, M.MarkerId, M.Title
FROM Markers AS M
HAVING distance < #Miles
ORDER BY M.DateStamp desc, Distance
I have tried
SELECT COUNT(MarkerId)
FROM Markers
HAVING (3959 * acos( cos( radians(#LAT) ) * cos( radians( Lat ) ) * cos(
radians( Lng ) - radians(#LNG) ) + sin( radians(#LAT) ) * sin( radians( Lat )
) ) ) < #Miles
but it fails trying to reference the Lat and Lng fields from the Markers table.
There are two methods. One is to use a subquery:
SELECT COUNT(*)
FROM (SELECT (3959 * acos( cos( radians(#LAT) ) * cos( radians( M.Lat ) ) * cos(
radians( M.Lng ) - radians(#LNG) ) + sin( radians(#LAT) ) * sin( radians(
M.Lat ) ) ) ) AS distance, M.MarkerId, M.Title
FROM Markers AS M
HAVING distance < #Miles
) x
The second method is to use SQL_CALC_FOUND_ROWS and then the FOUND_ROWS() function:
SELECT SQL_CALC_FOUND_ROWS (3959 * acos( cos( radians(#LAT) ) * cos( radians( M.Lat ) ) * cos(
radians( M.Lng ) - radians(#LNG) ) + sin( radians(#LAT) ) * sin( radians(
M.Lat ) ) ) ) AS distance, M.MarkerId, M.Title
FROM Markers AS M
HAVING distance < #Miles
ORDER BY M.DateStamp desc, Distance ;
SELECT FOUND_ROWS();
$str1="select SQL_CALC_FOUND_ROWS (3959 * acos( cos( radians(#LAT) ) * cos( radians( M.Lat ) ) * cos(
radians( M.Lng ) - radians(#LNG) ) + sin( radians(#LAT) ) * sin( radians(
M.Lat ) ) ) ) AS distance, M.MarkerId, M.Title
FROM Markers AS M
HAVING distance < #Miles
ORDER BY M.DateStamp desc, Distance limit ".$offset.",".$limit;
$q1 = mysql_query($str1);
$result=array();
$str2="SELECT FOUND_ROWS() AS Count";
$q2 = mysql_query($str2);
while($objCount= $q2->fetch_assoc()) {
$result["TotalRows"] = $objCount['Count'];
}
if ($q1->num_rows > 0) {
$result["Rows"] = mysql_result($q1);
} else {
$result["Rows"] = array();
}
return $result;
Related
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.
I am trying to to build a basic sql query where I have a table of petrol stations and another table of POI in my sql database and I would like to get all petrol stations within a radius of a POI
I have the following query:
SELECT *, ( 6371000 * acos( cos( radians(15.4383252) )
* cos( radians( petrol_stations.lat ) ) * cos( radians( petrol_stations.lng ) - radians(47.0450591) )
+ sin( radians(15.4383252) ) * sin(radians(petrol_stations.lat)) ) )
AS distance FROM petrol_stations HAVING distance < 500
and it seems to work fine, however I have to hard-code the coordinates of the POI into the query. Is it possible to adapt the query such that the POI coordinates are pulled from the other table if provided with the name such as main square?
Thanks in advance.
assuming you have a georef poi table as
table_poi
id name lat lng
1 my_poi 47.0450591 15.4383252
you could try a cross join for related all your petrol_stations with all your POI
SELECT *
, ( 6371000 * acos( cos( radians(table_poi.lng) )
* cos( radians( petrol_stations.lat ) ) * cos( radians( petrol_stations.lng )
- radians(table_poi.lat) )
+ sin( radians(table_poi.lng) ) * sin(radians(petrol_stations.lat)) ) )
AS distance
FROM petrol_stations
CROSS JOIN table_poi
HAVING distance < 500
or using where (as requested by MarlinPierce)
SELECT *
, ( 6371000 * acos( cos( radians(table_poi.lng) )
* cos( radians( petrol_stations.lat ) ) * cos( radians( petrol_stations.lng )
- radians(table_poi.lat) )
+ sin( radians(table_poi.lng) ) * sin(radians(petrol_stations.lat)) ) )
AS distance
FROM petrol_stations
CROSS JOIN table_poi
WHERE ( 6371000 * acos( cos( radians(table_poi.lng) )
* cos( radians( petrol_stations.lat ) ) * cos( radians( petrol_stations.lng )
- radians(table_poi.lat) )
+ sin( radians(table_poi.lng) ) * sin(radians(petrol_stations.lat)) ) ) < 500
and if you want filter for a POI name
SELECT *
, ( 6371000 * acos( cos( radians(table_poi.lng) )
* cos( radians( petrol_stations.lat ) ) * cos( radians( petrol_stations.lng )
- radians(table_poi.lat) )
+ sin( radians(table_poi.lng) ) * sin(radians(petrol_stations.lat)) ) )
AS distance
FROM petrol_stations
WHERE table_poi.name like '%your_poi_name%'
CROSS JOIN table_poi
HAVING distance < 500
I am making an application where Item will be delivered from one place to another. The database saves the sending location or address (along with the sending latitude and longitude) and the receiving address or location(along with the destination latitude and longitude).
I am making a search application which will receive data like
sending_latitude $Flat
Sending_longitude $Flon
Destination_latitude $Tlat
Destination_longitude $Tlon
From_date $date
Radius $r
Then it will search the item list to find the locations of the points within the specified radius parameter of the given geographic position and having the date matching from_date.
My Query:
SELECT *, (
6371 *
acos(
cos( radians( $Flat ) ) *
cos( radians( `sending_from_latitude` ) ) *
cos(
radians( `sending_from_longitude` ) - radians( $Flon )
) +
sin(radians($Flat)) *
sin(radians(`sending_from_latitude`))
)
) `senddistance`, (
6371 *
acos(
cos( radians( $Tlat ) ) *
cos( radians( `sending_to_latitude` ) ) *
cos(
radians( `sending_to_longitude` ) - radians( $Tlon )
) +
sin(radians($Tlat)) *
sin(radians(`sending_to_latitude`))
)
) `todistance`
FROM `items` as Item
HAVING (`senddistance` < $rad AND `todistance` < $rad)
ORDER BY `senddistance`
It's working fine as anticipated. However, I want to add another conditing AND from_date = $date in the Conditions.
So I wrote the query like this:
Modified Query:
SELECT *, (
6371 *
acos(
cos( radians( $Flat ) ) *
cos( radians( `sending_from_latitude` ) ) *
cos(
radians( `sending_from_longitude` ) - radians( $Flon )
) +
sin(radians($Flat)) *
sin(radians(`sending_from_latitude`))
)
) `senddistance`, (
6371 *
acos(
cos( radians( $Tlat ) ) *
cos( radians( `sending_to_latitude` ) ) *
cos(
radians( `sending_to_longitude` ) - radians( $Tlon )
) +
sin(radians($Tlat)) *
sin(radians(`sending_to_latitude`))
)
) `todistance`
FROM `items` as Item
WHERE from_date = $date
HAVING (`senddistance` < $rad AND `todistance` < $rad)
ORDER BY `senddistance`
It just simply returns empty result.
What am I doing wrong?
Have you tried to replace HAVINGwith WHERE?
HAVINGis typically used for filtering after you applied GROUP BY
WHEREfilters results before grouping
if the condition is for the query you must add where
You don't need the () around the having condition for this case
SELECT *, (
6371 *
acos(
cos( radians( $Flat ) ) *
cos( radians( `sending_from_latitude` ) ) *
cos(
radians( `sending_from_longitude` ) - radians( $Flon )
) +
sin(radians($Flat)) *
sin(radians(`sending_from_latitude`))
)
) `senddistance`, (
6371 *
acos(
cos( radians( $Tlat ) ) *
cos( radians( `sending_to_latitude` ) ) *
cos(
radians( `sending_to_longitude` ) - radians( $Tlon )
) +
sin(radians($Tlat)) *
sin(radians(`sending_to_latitude`))
)
) `todistance`
FROM `items` as Item
WHERE from_date = $date
HAVING `senddistance` < $rad AND `todistance` < $rad
ORDER BY `senddistance`
In the condition is for filtering the result after group by then you can add the condition in having clause and however you don't need ()
SELECT *, (
6371 *
acos(
cos( radians( $Flat ) ) *
cos( radians( `sending_from_latitude` ) ) *
cos(
radians( `sending_from_longitude` ) - radians( $Flon )
) +
sin(radians($Flat)) *
sin(radians(`sending_from_latitude`))
)
) `senddistance`, (
6371 *
acos(
cos( radians( $Tlat ) ) *
cos( radians( `sending_to_latitude` ) ) *
cos(
radians( `sending_to_longitude` ) - radians( $Tlon )
) +
sin(radians($Tlat)) *
sin(radians(`sending_to_latitude`))
)
) `todistance`
FROM `items` as Item
HAVING `senddistance` < $rad
AND `todistance` < $rad
AND from_date = $date
ORDER BY `senddistance`
anyway do the fact you are not using aggregation function and you don't have group bu then you don't should use having but only where
SELECT *, (
6371 *
acos(
cos( radians( $Flat ) ) *
cos( radians( `sending_from_latitude` ) ) *
cos(
radians( `sending_from_longitude` ) - radians( $Flon )
) +
sin(radians($Flat)) *
sin(radians(`sending_from_latitude`))
)
) `senddistance`, (
6371 *
acos(
cos( radians( $Tlat ) ) *
cos( radians( `sending_to_latitude` ) ) *
cos(
radians( `sending_to_longitude` ) - radians( $Tlon )
) +
sin(radians($Tlat)) *
sin(radians(`sending_to_latitude`))
)
) `todistance`
FROM `items` as Item
WHERE from_date = $date
AND `senddistance` < $rad
AND `todistance` < $rad
ORDER BY `senddistance`
First part of the query:
SET #centerLat = '48.531157';
SET #centerLng = '-123.782959';
SELECT user_id, lat, lng, ( 3959 * acos( cos( radians( #centerLat ) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(#centerLng) ) + sin( radians( #centerLat ) ) * sin( radians( lat ) ) ) ) AS distance FROM bid_userloc HAVING distance < 25 ORDER BY distance LIMIT 0 , 20
Second aspect is taking the user_id and grabbing a bunch of information from the USERS table
I'm still learning what JOIN even means and I don't quite understand how it all works best...
you may try this
SELECT user_id, lat, lng, ( 3959 * acos( cos( radians( #centerLat ) )
* cos( radians( lat ) ) * cos( radians( lng ) - radians(#centerLng) )
+ sin( radians( #centerLat ) ) * sin( radians( lat ) ) ) )
AS distance,columnsfromuserstable FROM bid_userloc bid
inner join users us on bid.user_id=us.user_id
HAVING distance < 25
ORDER BY distance LIMIT 0 , 20
You can try something like this:
select * from users where user_id in (select user_id from(
SELECT user_id, lat, lng, ( 3959 * acos( cos( radians( #centerLat ) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(#centerLng) ) + sin( radians( #centerLat ) ) * sin( radians( lat ) ) ) ) AS distance FROM bid_userloc HAVING distance < 25 ORDER BY distance LIMIT 0 , 20
));
Variant with JOIN -
SET #centerLat = '48.531157';
SET #centerLng = '-123.782959';
SELECT
t1.user_id, t1.lat, t1.lng,
(3959 * ACOS(COS(RADIANS(#centerLat)) * COS(RADIANS(t1.lat)) * COS(RADIANS(t1.lng) - RADIANS(#centerLng)) + SIN(RADIANS(#centerLat)) * SIN(RADIANS(t1.lat)))) distance,
t2.*
FROM
bid_userloc t1
JOIN users t2
ON t1.user_id = t2.user_id
HAVING
distance < 25
ORDER BY
distance
LIMIT
0, 20;
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