my first time using one of these and I'm pretty sure this works as I have picked it up on Stackoverflow how ever when I run it as an SQL command it fails. This seems to be a common problem and having tried several different sets of code I seem to get the same problem....
MySQL said:
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 '$$ CREATE FUNCTION GetDistance(coordinate1 VARCHAR(120),
coordinate2 VARCHAR(' at line 1
DROP FUNCTION IF EXISTS `GetDistance`$$
CREATE FUNCTION `GetDistance`(coordinate1 VARCHAR(120), coordinate2 VARCHAR(120))
RETURNS VARCHAR(120)
BEGIN
DECLARE pos_comma1, pos_comma2 INT;
DECLARE lon1, lon2, lat1, lat2, distance DECIMAL(18,12);
select locate(',', coordinate1) into pos_comma1;
select locate(',', coordinate1, pos_comma1+1) into pos_comma2;
select CAST(substring(coordinate1, 1, pos_comma1-1) as DECIMAL(18,12)) into lon1;
select CAST(substring(coordinate1, pos_comma1+1, pos_comma2-pos_comma1-1) as DECIMAL(18,12)) into lat1;
select locate(',', coordinate2) into pos_comma1;
select locate(',', coordinate2, pos_comma1+1) into pos_comma2;
select CAST(substring(coordinate2, 1, pos_comma1-1) as DECIMAL(18,12)) into lon2;
select CAST(substring(coordinate2, pos_comma1+1, pos_comma2-pos_comma1-1) as DECIMAL(18,12)) into lat2;
select ((ACOS(SIN(lat1 * PI() / 180) * SIN(lat2 * PI() / 180) + COS(lat1 * PI() / 180) * COS(lat2 * PI() / 180) * COS((lon1 - lon2) * PI() / 180)) * 180 / PI()) * 60 * 1.1515) into distance;
RETURN distance;
END$$
Thanks - Terran
EDIT
Tried..........
DROP FUNCTION IF EXISTS `GetDistance`;
delimiter $$
CREATE FUNCTION `GetDistance`(coordinate1 VARCHAR(120), coordinate2 VARCHAR(120))
RETURNS VARCHAR(120)
BEGIN
DECLARE pos_comma1, pos_comma2 INT;
DECLARE lon1, lon2, lat1, lat2, distance DECIMAL(18,12);
select locate(',', coordinate1) into pos_comma1;
select locate(',', coordinate1, pos_comma1+1) into pos_comma2;
select CAST(substring(coordinate1, 1, pos_comma1-1) as DECIMAL(18,12)) into lon1;
select CAST(substring(coordinate1, pos_comma1+1, pos_comma2-pos_comma1-1) as DECIMAL(18,12)) into lat1;
select locate(',', coordinate2) into pos_comma1;
select locate(',', coordinate2, pos_comma1+1) into pos_comma2;
select CAST(substring(coordinate2, 1, pos_comma1-1) as DECIMAL(18,12)) into lon2;
select CAST(substring(coordinate2, pos_comma1+1, pos_comma2-pos_comma1-1) as DECIMAL(18,12)) into lat2;
select ((ACOS(SIN(lat1 * PI() / 180) * SIN(lat2 * PI() / 180) + COS(lat1 * PI() / 180) * COS(lat2 * PI() / 180) * COS((lon1 - lon2) * PI() / 180)) * 180 / PI()) * 60 * 1.1515) into distance;
RETURN distance;
END;
$$
and..........
DROP FUNCTION IF EXISTS `GetDistance`;
$$
CREATE FUNCTION `GetDistance`(coordinate1 VARCHAR(120), coordinate2 VARCHAR(120))
RETURNS VARCHAR(120)
BEGIN
DECLARE pos_comma1, pos_comma2 INT;
DECLARE lon1, lon2, lat1, lat2, distance DECIMAL(18,12);
select locate(',', coordinate1) into pos_comma1;
select locate(',', coordinate1, pos_comma1+1) into pos_comma2;
select CAST(substring(coordinate1, 1, pos_comma1-1) as DECIMAL(18,12)) into lon1;
select CAST(substring(coordinate1, pos_comma1+1, pos_comma2-pos_comma1-1) as DECIMAL(18,12)) into lat1;
select locate(',', coordinate2) into pos_comma1;
select locate(',', coordinate2, pos_comma1+1) into pos_comma2;
select CAST(substring(coordinate2, 1, pos_comma1-1) as DECIMAL(18,12)) into lon2;
select CAST(substring(coordinate2, pos_comma1+1, pos_comma2-pos_comma1-1) as DECIMAL(18,12)) into lat2;
select ((ACOS(SIN(lat1 * PI() / 180) * SIN(lat2 * PI() / 180) + COS(lat1 * PI() / 180) * COS(lat2 * PI() / 180) * COS((lon1 - lon2) * PI() / 180)) * 180 / PI()) * 60 * 1.1515) into distance;
RETURN distance;
END;
$$
Both fail....
Terran
EDIT - Found this working script.... LINK: http://datamoil.blogspot.co.uk/2011/09/calculate-distance-between-two-points.html
CREATE FUNCTION distance_between (from_lat DECIMAL(6, 3), from_lng DECIMAL(6, 3), to_lat DECIMAL(6, 3), to_lng DECIMAL(6, 3)) RETURNS DECIMAL(11, 3)
RETURN 6371 * 2 * ATAN2(SQRT(POW(SIN(RADIANS(to_lat - from_lat)/2), 2) + POW(SIN(RADIANS(to_lng - from_lng)/2), 2) * COS(RADIANS(from_lat)) * COS(RADIANS(to_lat))), SQRT(1 - POW(SIN(RADIANS(to_lat - from_lat)/2), 2) + POW(SIN(RADIANS(to_lng - from_lng)/2), 2) * COS(RADIANS(from_lat)) * COS(RADIANS(to_lat))));
DROP FUNCTION IF EXISTS `GetDistance`;
delimiter $$
CREATE FUNCTION `GetDistance`...
...
RETURN distance;
END;
$$
You have to change your delimiter to $$ before executing this code.
This works for me (tested on MySql)
DROP FUNCTION IF EXISTS `GetDistance`;
delimiter $$
CREATE FUNCTION `GetDistance`(coordinate1 VARCHAR(120), coordinate2 VARCHAR(120))
RETURNS VARCHAR(120)
BEGIN
DECLARE pos_comma1, pos_comma2 INT;
DECLARE lon1, lon2, lat1, lat2, distance DECIMAL(18,12);
select locate(',', coordinate1) into pos_comma1;
select locate(',', coordinate1, pos_comma1+1) into pos_comma2;
select CAST(substring(coordinate1, 1, pos_comma1-1) as DECIMAL(18,12)) into lon1;
select CAST(substring(coordinate1, pos_comma1+1, pos_comma2-pos_comma1-1) as DECIMAL(18,12)) into lat1;
select locate(',', coordinate2) into pos_comma1;
select locate(',', coordinate2, pos_comma1+1) into pos_comma2;
select CAST(substring(coordinate2, 1, pos_comma1-1) as DECIMAL(18,12)) into lon2;
select CAST(substring(coordinate2, pos_comma1+1, pos_comma2-pos_comma1-1) as DECIMAL(18,12)) into lat2;
select ((ACOS(SIN(lat1 * PI() / 180) * SIN(lat2 * PI() / 180) + COS(lat1 * PI() / 180) * COS(lat2 * PI() / 180) * COS((lon1 - lon2) * PI() / 180)) * 180 / PI()) * 60 * 1.1515) into distance;
RETURN distance;
END;
$$
Related
I really wanna know why place B is more far than place C to place A, when i use Haversine formula, but when i see on the map the place C is more distant, i will show some data:
Place A - lat: -23.598593 lon:-46.644701
Place B - lat: -23.575966 lon:-46.619133 to A distance = 3.6117730949107836
Place C - lat: -23.594992 lon:-46.636688 to A distance = 0.9068309093558656
I'm using this query :
QUERY A to B
set #latdest = -23.575966;
set #londest = -46.619133;
set #lat = -23.598593;
set #lon = -46.644701;
select 6353 * 2 * ASIN(SQRT(POWER(SIN((#lat - #latdest) * pi()/180 / 2), 2)
+ COS(#lat * pi()/180 ) * COS(#latdest * pi()/180)
* POWER(SIN((#lon - #londest) * pi()/180 / 2), 2) )) as distance
QUERY A to C
set #latdest = -23.594992;
set #londest = -46.636688;
set #lat = -23.598593;
set #lon = -46.644701;
select 6353 * 2 * ASIN(SQRT(POWER(SIN((#lat - #latdest) * pi()/180 / 2), 2)
+ COS(#lat * pi()/180 ) * COS(#latdest * pi()/180)
* POWER(SIN((#lon - #londest) * pi()/180 / 2), 2) )) as distance
I have created a table where I store Lat/Long. data along with ZIP codes.
Here is my procedure to find ZIPs within certain radius:
CREATE PROCEDURE geodistZCTA (IN userid char(5), IN dist double)
BEGIN
declare mylon double;
declare mylat double;
declare lon1 float;
declare lon2 float;
declare lat1 float;
declare lat2 float;
-- get the original lon and lat for the userid
select Y(location), X(location) into mylon, mylat from zcta where zip=userid limit 1;
-- calculate lon and lat for the rectangle:
set lon1 = mylon-dist/abs(cos(radians(mylat))*69);
set lon2 = mylon+dist/abs(cos(radians(mylat))*69);
set lat1 = mylat-(dist/69);
set lat2 = mylat+(dist/69);
-- run the query:
-- select astext(location), zip from zcta where st_within(location, envelope(linestring(point(lon1, lat1), point(lon2, lat2)))) order by st_distance(point(mylon, mylat), location) limit 10;
-- select zip,(3956 * 2 * ASIN(SQRT(POWER(SIN((lat1 - abs(lat2)) * pi()/180 / 2), 2) + COS(abs(lat1) * pi()/180 ) * COS(abs(lat2) * pi()/180) * POWER(SIN((lon1 - lon2) * pi()/180 / 2), 2) ))) AS distance FROM zcta HAVING distance<=dist ORDER BY distance ASC;
-- SELECT zip,X(location),Y(location),(((ACOS(SIN(mylat * PI() / 180) * SIN(X(location) * PI() / 180) + COS(mylat * PI() / 180) * COS(X(location) * PI() / 180) * COS((Y(location)-mylon) * PI() / 180)) * 180 / PI()) * 60 * 1.1515)) AS distance FROM zcta HAVING distance<=dist ORDER BY distance ASC;
select zip,X(location),Y(location),
( 3959 * acos( cos( radians(mylat) )
* cos( radians( X(location) ) )
* cos( radians( Y(location) ) - radians(mylon) )
+ sin( radians(mylat) )
* sin( radians( X(location) ) ) ) ) AS distance
FROM zcta
where X(location) between lat1 and lat2
and Y(location) between lon1 and lon2
HAVING distance <= dist ORDER BY distance ASC;
END;
Now when I call the procedure like:
call geodistZCTA('03804',5);
I get the following result:
# zip, X(location), Y(location), distance
-------------------------------------------------------
'03042', '43.045076', '-71.07095', '3.9798046354127266'
But when I measure the distance using http://www.allplaces.us/dbz.cgi
I get 16.2 miles ( 26.1 km )
Any idea of what I am doing wrong here?
I have a query that creates two aliased files like this:
(CASE WHEN `venueID` > 0 THEN `venueLongitude` ELSE `specialLongitude` END) AS `longitude`
(CASE WHEN `venueID` > 0 THEN `venueLatitude` ELSE `specialLatitude` END) AS `latitude`
which determine which longitude and latitude to use in a certain query (there are numerous JOIN's in the table, but for the sake of this example, the only JOIN is from the Gigs table performing a NATURAL LEFT JOIN to a table called Venues.
That bit works fine and returns the venue co-ordinates I am interested in doing a distance calculation that I can then order by.
The distance field looks like this:
((ACOS(SIN($lat * PI() / 180) * SIN(`latitude` * PI() / 180) + COS($lat * PI() / 180) * COS(`latitude` * PI() / 180) * COS(($lon - `longitude`) * PI() / 180)) * 180 / PI()) * 60 * 1.1515)
But when I run the query, I get the error Unknown column 'latitude' in 'field list'. Does anyone know how I can perform such a lookup.
p.s.
Although I know I can use geospatial queries, I would like to know the answer in a way that could later be used for further queries, i.e.
SELECT *,(CASE WHEN `a` > 0 THEN `a` ELSE `b` END) AS `x`,(`x` MOD 3) AS `y` FROM `Foo`
2 ways :
a) replace the aliases with SQL
b) Encapsulate your first query by another one like this :
SELECT
t.latitude,
t.longitude,
((ACOS(SIN($lat * PI() / 180) * SIN(t.latitude * PI() / 180) + COS($lat * PI() / 180) * COS(latitude * PI() / 180) * COS(($lon - t.longitude) * PI() / 180)) * 180 / PI()) * 60 * 1.1515) as distance
FROM (
SELECT ((CASE WHEN `venueID` > 0 THEN `venueLongitude` ELSE `specialLongitude` END) AS `longitude`, (CASE WHEN `venueID` > 0 THEN `venueLatitude` ELSE `specialLatitude` END) AS `latitude` FROM Gigs left join Venues on ....
) as t
If you want to SELECT the distance, then I believe you need to re-declare the case for the value. AKA: Rather than using SELECT col alias1, alias1 + 1 alias2 you have to do SELECT col alias1, col + 1 alias2. Take a look at this MySQL documentation on Where you can use column aliases.
If you just want to GROUP BY the distance, then you can use your aliases in your distance function. However, if you want to SELECT the distance, you need to replace the alias usage in your distance function with the evaluated CASE code.
ORDER BY using aliases:
SELECT
(CASE WHEN `venueID` > 0 THEN `venueLongitude` ELSE `specialLongitude` END) longitude,
(CASE WHEN `venueID` > 0 THEN `venueLatitude` ELSE `specialLatitude` END) latitude
FROM table_name
ORDER BY ((ACOS(SIN(latitude * PI() / 180) * SIN(latitude * PI() / 180) + COS(latitude * PI() / 180) * COS(latitude * PI() / 180) * COS(longitude * PI() / 180)) * 180 / PI()) * 60 * 1.1515)
SELECT cannot use the aliases (it gets messy!):
SELECT
(CASE WHEN `venueID` > 0 THEN `venueLongitude` ELSE `specialLongitude` END) longitude,
(CASE WHEN `venueID` > 0 THEN `venueLatitude` ELSE `specialLatitude` END) latitude,
(
((ACOS(SIN((CASE WHEN `venueID` > 0 THEN `venueLatitude` ELSE `specialLatitude` END) * PI() / 180) * SIN((CASE WHEN `venueID` > 0 THEN `venueLatitude` ELSE `specialLatitude` END) * PI() / 180) + COS((CASE WHEN `venueID` > 0 THEN `venueLatitude` ELSE `specialLatitude` END) * PI() / 180) * COS((CASE WHEN `venueID` > 0 THEN `venueLatitude` ELSE `specialLatitude` END) * PI() / 180) * COS((CASE WHEN `venueID` > 0 THEN `venueLongitude` ELSE `specialLongitude` END) * PI() / 180)) * 180 / PI()) * 60 * 1.1515)
) distance
FROM table_name
ORDER BY distance
I'm using a slightly-modified version of the geocoded gem which returns this query when I call near on my model (calling Deal.near(southwest), where southwest is an array of geo coordinates):
SELECT
deals.*,
3958.755864232 * 2 * ASIN(SQRT(POWER(SIN((37.772476604436974 - addresses.lat) * PI() / 180 / 2), 2) + COS(37.772476604436974 * PI() / 180) * COS(addresses.lat * PI() / 180) * POWER(SIN((-122.42336332798004 - addresses.lng) * PI() / 180 / 2), 2) )) AS distance,
CAST(DEGREES(ATAN2( RADIANS(addresses.lng - -122.42336332798004), RADIANS(addresses.lat - 37.772476604436974))) + 360 AS decimal) % 360 AS bearing
FROM "deals"
INNER JOIN "companies" ON "companies"."id" = "deals"."company_id"
INNER JOIN "addresses" ON "addresses"."addressable_id" = "companies"."id" AND "addresses"."addressable_type" = 'Company'
WHERE (
addresses.lat BETWEEN 37.483013038215276 AND 38.06194017065867
AND addresses.lng BETWEEN -122.78956461309022 AND -122.05716204286986
)
GROUP BY
deals.id,
deals.created_at,
deals.updated_at,
deals.active,
deals.company_id,
deals.title,
deals.limitations,
deals.redemption_count,
addresses.lat,
addresses.lng
HAVING 3958.755864232 * 2 * ASIN(SQRT(POWER(SIN((37.772476604436974 - addresses.lat) * PI() / 180 / 2), 2) + COS(37.772476604436974 * PI() / 180) * COS(addresses.lat * PI() / 180) * POWER(SIN((-122.42336332798004 - addresses.lng) * PI() / 180 / 2), 2) )) <= 20
ORDER BY 3958.755864232 * 2 * ASIN(SQRT(POWER(SIN((37.772476604436974 - addresses.lat) * PI() / 180 / 2), 2) + COS(37.772476604436974 * PI() / 180) * COS(addresses.lat * PI() / 180) * POWER(SIN((-122.42336332798004 - addresses.lng) * PI() / 180 / 2), 2) )) ASC
My issue is that this will return multiple Deal records if that Deal's company has multiple Addresses, which I don't want.
In MySQL, I could just omit address.lat, address.lng in the GROUP_BY clause and it will properly group the records, but I can't do this in PostgreSQL.
I know I could wrap the whole query above in another SELECT and GROUP_BY, like this:
SELECT
id, created_at, updated_at, active, title, punches_to_complete, company_id, description, lat, lng, MIN(distance), bearing
FROM ( ... ) AS t
GROUP BY company_id
... where the ellipsis is the query from above. That (I believe) should get me the desired result in both MySQL and PostgreSQL.
The only problem is that I have no idea how to write this in ARel!
I had tried the following, a la this tip from the ARel guru, but I couldn't really make it work quite right (calling to_sql as the OP had said fixed his issue escapes the quotes, which freaks PostgreSQL out).
Can anyone help me with this???
UPDATE:
I've managed to get this done with an additional scope, like so:
scope :nearest, lambda { |coords|
subquery = "(#{Deal.near(coords).to_sql}) AS t1"
columns = Deal.columns.map{ |c| c.name }.join(',')
Deal.select(columns)
.select('MIN(distance) AS distance')
.from(subquery)
.group(columns)
.order('distance ASC')
}
However, this totally breaks chainability, as now I cannot call something like current_user.deals.nearest(coords), since that tags on an additional WHERE deals.user_id = 1 to the query outside of the subselect. I tried compensating for this by moving this logic into a class method and blanking the wheres clause on the SelectManager manually, like this:
def self.nearest(coords)
subquery = "(#{Deal.near(coords).to_sql}) AS t1"
columns = Deal.columns.map{ |c| c.name }.join(',')
query = Deal.select(columns)
.select('MIN(distance) AS distance')
.from(subquery)
.group(columns)
.order('distance ASC')
query.arel.ast.cores[0].wheres = []
query
end
... but that doesn't seem to work either: the additional WHERE clause is still appended:
Failure/Error:
#user.deals.nearest(southwest).first.distance.to_f.round(2).should ==
ActiveRecord::StatementInvalid:
Mysql2::Error: Unknown column 'deals.user_id' in 'where
clause': SELECT id,created_at,updated_at,user_id,company_id,
MIN(distance) AS distance FROM (SELECT deals.*, 3958.755864232 * 2 *
ASIN(SQRT(POWER(SIN((37.772476604436974 - addresses.lat) * PI() / 180
/ 2), 2) + COS(37.772476604436974 * PI() / 180) * COS(addresses.lat *
PI() / 180) * POWER(SIN((-122.42336332798004 - addresses.lng) * PI() /
180 / 2), 2) )) AS distance, CAST(DEGREES(ATAN2( RADIANS(addresses.lng
- -122.42336332798004), RADIANS(addresses.lat - 37.772476604436974)))
+ 360 AS decimal) % 360 AS bearing FROM deals INNER JOIN companies
ON companies.id = deals.company_id INNER JOIN addresses ON
addresses.addressable_id = companies.id AND
addresses.addressable_type = 'Company' WHERE deals.user_id =
26 AND (addresses.lat BETWEEN 37.483013038215276 AND 38.06194017065867
AND addresses.lng BETWEEN -122.78956461309022 AND -122.05716204286986)
GROUP BY
deals.id,deals.created_at,deals.updated_at,deals.user_id,deals.company_id,
addresses.lat, addresses.lng HAVING 3958.755864232 * 2 *
ASIN(SQRT(POWER(SIN((37.772476604436974 - addresses.lat) * PI() / 180
/ 2), 2) + COS(37.772476604436974 * PI() / 180) * COS(addresses.lat *
PI() / 180) * POWER(SIN((-122.42336332798004 - addresses.lng) * PI() /
180 / 2), 2) )) <= 20 ORDER BY 3958.755864232 * 2 *
ASIN(SQRT(POWER(SIN((37.772476604436974 - addresses.lat) * PI() / 180
/ 2), 2) + COS(37.772476604436974 * PI() / 180) * COS(addresses.lat *
PI() / 180) * POWER(SIN((-122.42336332798004 - addresses.lng) * PI() /
180 / 2), 2) )) ASC) AS t1 WHERE deals.user_id = 26 GROUP BY
id,created_at,updated_at,user_id,company_id ORDER BY distance ASC
LIMIT 1
Is what I'm trying to do even possible with ARel? The additional scopes above feel really dirty to me (parsing the subquery to raw SQL? I thought ARel was supposed to make it so I never did that!)
Related question: Can ARel formulate cross-db queries for CTEs (Common Table Expressions)?
I get Latitude and Longitudes from Google Maps Reverse-Geocoding API and then I need something like this:
mysql_query("SELECT users.*, ".mysql_distance_column($lat,$lng)." FROM users ORDER BY DISTANCE";
function mysql_distance_column($lat=40 , $lng=-73) {
$defaultLatitudeColumn = 'user_lat';
$defaultLongitudeColumn='user_lng';
$defaultColumnName='user_distance';
return "((
(3956 * 2 * ASIN(SQRT( POWER(SIN(({$lat} - abs({$defaultLatitudeColumn}))
* pi()/180 / 2), 2) + COS({$lat} * pi()/180 )
* COS(abs({$defaultLatitudeColumn}) * pi()/180)
* POWER(SIN(({$lng} - {$defaultLongitudeColumn}) * pi()/180 / 2), 2) ))
)) ) as {$defaultColumnName} ";
}
UPDATE
I cant ge this to work
delimiter //
CREATE FUNCTION `GeoDistMiles`( lat1 FLOAT (10,6), lon1 FLOAT (10,6), lat2 FLOAT (10,6), lon2 FLOAT (10,6) )
RETURNS FLOAT
DETERMINISTIC
NO SQL
BEGIN
DECLARE pi, q1, q2, q3 FLOAT (10,6);
DECLARE rads FLOAT (10,6) DEFAULT 0;
SET pi = PI();
SET lat1 = lat1 * pi / 180;
SET lon1 = lon1 * pi / 180;
SET lat2 = lat2 * pi / 180;
SET lon2 = lon2 * pi / 180;
SET q1 = COS(lon1-lon2);
SET q2 = COS(lat1-lat2);
SET q3 = COS(lat1+lat2);
SET rads = ACOS( 0.5*((1.0+q1)*q2 - (1.0-q1)*q3) );
RETURN 3963.346 * rads;
END
Here is the formula I use. Remember that the Earth is not a perfect sphere, so the results will never be perfect.
CREATE DEFINER=`root`#`localhost` FUNCTION `GeoDistMiles`( lat1 FLOAT, lon1 FLOAT, lat2 FLOAT, lon2 FLOAT ) RETURNS float
BEGIN
DECLARE pi, q1, q2, q3 FLOAT;
DECLARE rads FLOAT DEFAULT 0;
SET pi = PI();
SET lat1 = lat1 * pi / 180;
SET lon1 = lon1 * pi / 180;
SET lat2 = lat2 * pi / 180;
SET lon2 = lon2 * pi / 180;
SET q1 = COS(lon1-lon2);
SET q2 = COS(lat1-lat2);
SET q3 = COS(lat1+lat2);
SET rads = ACOS( 0.5*((1.0+q1)*q2 - (1.0-q1)*q3) );
RETURN 3963.346 * rads;
END
I assume that you are trying to use http://en.wikipedia.org/wiki/Haversine_formula.
This is lightly tested, but I think that your formula should be:
(ROUND((3956 * 2 * ASIN(SQRT(POWER(SIN(({$lat} - {$defaultLatitudeColumn}) * pi() / 180 / 2), 2) + COS({$lat} * pi()/180 ) * COS({$defaultLatitudeColumn} * pi()/180) *POWER(SIN(({$lng} - {$defaultLongitudeColumn}) * pi()/180 / 2), 2) )) )*{$magicNumber}) )/{$magicNumber}
(I removed the abs calls.)
Hi I have a simple procedure you can use it for your work.
The procedure is very simple and calculate the distance between two cities.you can modify it in your way.
drop procedure if exists select_lattitude_longitude;
delimiter //
create procedure select_lattitude_longitude(In CityName1 varchar(20) , In CityName2 varchar(20))
begin
declare origin_lat float(10,2);
declare origin_long float(10,2);
declare dest_lat float(10,2);
declare dest_long float(10,2);
if CityName1 Not In (select Name from City_lat_lon) OR CityName2 Not In (select Name from City_lat_lon) then
select 'The Name Not Exist or Not Valid Please Check the Names given by you' as Message;
else
select lattitude into origin_lat from City_lat_lon where Name=CityName1;
select longitude into origin_long from City_lat_lon where Name=CityName1;
select lattitude into dest_lat from City_lat_lon where Name=CityName2;
select longitude into dest_long from City_lat_lon where Name=CityName2;
select origin_lat as CityName1_lattitude,
origin_long as CityName1_longitude,
dest_lat as CityName2_lattitude,
dest_long as CityName2_longitude;
SELECT 3956 * 2 * ASIN(SQRT( POWER(SIN((origin_lat - dest_lat) * pi()/180 / 2), 2) + COS(origin_lat * pi()/180) * COS(dest_lat * pi()/180) * POWER(SIN((origin_long-dest_long) * pi()/180 / 2), 2) )) * 1.609344 as Distance_In_Kms ;
end if;
end ;
//
delimiter ;
SELECT ACOS(COS(RADIANS(lat)) *
COS(RADIANS(lon)) * COS(RADIANS(34.7405350)) * COS(RADIANS(-92.3245120)) +
COS(RADIANS(lat)) * SIN(RADIANS(lon)) * COS(RADIANS(34.7405350)) *
SIN(RADIANS(-92.3245120)) + SIN(RADIANS(lat)) * SIN(RADIANS(34.7405350))) *
3963.1 AS Distance
FROM Stores
WHERE 1
HAVING Distance <= 50
Here's how I use it in PHP:
// Find rows in Stores within 50 miles of $lat,$lon
$lat = '34.7405350';
$lon = '-92.3245120';
$sql = "SELECT Stores.*, ACOS(COS(RADIANS(lat)) *
COS(RADIANS(lon)) * COS(RADIANS($lat)) * COS(RADIANS($lon)) +
COS(RADIANS(lat)) * SIN(RADIANS(lon)) * COS(RADIANS($lat)) *
SIN(RADIANS($lon)) + SIN(RADIANS(lat)) * SIN(RADIANS($lat))) *
3963.1 AS Distance
FROM Stores
WHERE 1
HAVING Distance <= 50";
3956 * 2 * ASIN(SQRT( POWER(SIN(($latitude -( cp.latitude)) * pi()/180 / 2),2) + COS($latitude * pi()/180 ) * COS( abs( cp.latitude) * pi()/180) * POWER(SIN(($longitude - cp.longitude) * pi()/180 / 2), 2) )) as distance
Returns miles or KM?