Smart SQL group by - mysql

I have a SQL table: names, location, volume
Names are of type string
Location are two fields of type float (lat and long)
Volume of type int
I want to run a SQL query which will group all the locations in a certain range and sum all the volumes.
For instance group all the locations from 1.001 to 2 degrees lat and 1.001 to 2 degrees long into one with all their volumes summed from 2.001 to 3 degrees lat and long and so on.
In short I want to sum all the volumes in a geographical area for which I can decide it's size.
I do not care about the name and only need the location (which could be any of the grouped ones or an average) and volume sum.
Here is a sample table:
CREATE TABLE IF NOT EXISTS `example` (
`name` varchar(12) NOT NULL,
`lat` float NOT NULL,
`lng` float NOT NULL,
`volume` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `example` (`name`, `lat`, `lng`, `volume`) VALUES
("one", 1.005, 1.007, 2),
("two", 1.25, 1.907, 3),
("three", 2.065, 65.007, 2),
("four", 2.905, 65.1, 10),
("five", 12.3, 43.8, 5),
("six", 12.35, 43.2, 2);
For which the return query for an area of size one degree could be:
1.005, 1.007, 5
2.065, 65.007, 12
12.3, 43.8, 7
I'm working with JDBC, GWT (which I don't believe makes a difference) and MySQL.

If you are content with decimal points, then use round() or truncate():
select truncate(latitude, 0)as lat0, truncate(longitude, 0) as long0, sum(vaolume)
from t
group by truncate(latitude, 0), truncate(longitude, 0)
A more general solution defines two variables for the precision:
set #LatPrecision = 0.25, #LatPrecision = 0.25
select floor(latitude/#LatPrecision)*#LatPrecision,
floor(longitude/#LongPrecision)*#LongPrecision,
sum(value)
from t
group by floor(latitude/#LatPrecision),
floor(longitude/#LongPrecision)*#LongPrecision

Convert latitude from float to int and then group by converted value. When the float is converted, say from 2.1 or 2.7, i think it becomes 2. Hence all values between 2.000 to 2.999 will have the same converted value of 2. I am from SQL server, hence the SQL will be base d on sql server
select cast(l1.latitude as int), cast(l2.latitude as int) sum(v.volume)
from location l1
join location l2 on cast(l1.latitude as int) = cast(l2.longitude as int)
join volume v
group by cast(latitude as int), cast(l2.latitude as int)

May be I am super late to send this answer:
sqlfiddle demo
Code:
select round(x.lat,4), round(x.lng,4),
sum(x.volume)
from (
select
case when lat >= 1.00 and lng <2
then 'loc1' end loc1,
case when lat >= 2.00 and lng <3
then 'loc2' end loc2,
case when lat >= 3.00 and lng >10
then 'loc3' end loc3,
lat, lng,
volume
from example) as x
group by x.loc1, x.loc2, x.loc3
order by x.lat, x.lng asc
;
Results:
ROUND(X.LAT,4) ROUND(X.LNG,4) SUM(X.VOLUME)
1.005 1.007 5
2.065 65.007 12
12.3 43.8 7

Related

Calculate sum when value changes

I am trying to build a system that will track vehicle fuelings, and have run into a problem with one report; determining fuel efficiency in distance/fuel. Sample data is:
odometer
fuel
partial_fillup
61290
10.3370
0
61542
6.4300
0
61735
4.3600
0
61994
7.5000
0
62242
5.4070
0
62452
8.1100
0
62713
5.7410
1
62876
9.4850
0
63243
6.1370
1
63499
10.7660
0
Where odometer is the total distance the vehicle has traveled, fuel is the number of gallons or liters put in, and partial_fillup is a boolean meaning the fuel tank was not completely filled if non-zero.
If the user fills the tank each time the query I can use is:
set #a = null;
select
odometer,
odometer-previousOdometer distance,
fuel,
(odometer-previousOdometer)/fuel mpg,
partial_fillup
from
(
select
#a as previousOdometer,
#a:=odometer,
odometer,
fuel/1000 fuel,
partial_fillup
from fuel
where
vehicle_id =1
and odometer >= 61290
order by odometer
) as readings
where readings.previousOdometer is not null;
However, when the user only partially fills the tank, the correct procedure would be to subtract the last full fueling from current odometer reading, then divide by the sum of all fuel since the previous odometer reading, so at odometer 63499, the calculate would be (63499-62876)/(10.7660+6.1370)
This will get the average used on the last ride:
select
odometer,
odometer-lag(odometer) over (order by odometer) as distance,
fuel,
(odometer-lag(odometer) over (order by odometer))/fuel as mpg
from fuel
output:
odometer
distance
fuel
mpg
61290
10.3370
61542
252
6.4300
39.1913
61735
193
4.3600
44.2661
61994
259
7.5000
34.5333
62242
248
5.4070
45.8665
62452
210
8.1100
25.8940
62713
261
5.7410
45.4625
62876
163
9.4850
17.1850
63243
367
6.1370
59.8012
63499
256
10.7660
23.7786
Or you can calculate the total drive distance, and the total amount of fuel used:
select
distance,
sum_fuel,
distance/sum_fuel as mpg
from (
select
f.odometer,
f.odometer-(select min(odometer) from fuel) as distance,
fuel,
sum_fuel
from fuel f
inner join (
select
odometer,
sum(fuel) over (order by R) as sum_fuel
from (
select
odometer,
fuel,
row_number() over (order by odometer) R
from fuel) x
) x on x.odometer = f.odometer
) x2
which will get next output, which will get closer to an average after a longer time of measurement:
distance
sum_fuel
mpg
0
10.3370
0.0000
252
16.7670
15.0295
445
21.1270
21.0631
704
28.6270
24.5922
952
34.0340
27.9720
1162
42.1440
27.5721
1423
47.8850
29.7170
1586
57.3700
27.6451
1953
63.5070
30.7525
2209
74.2730
29.7416
DBFIDDLE
I was able to figure it out after studying Luuk's answer. I'm sure there is a more efficient way to do this; I am not used to using variables in SQL. But, the answers are correct in the test data.
set #oldOdometer = null;
set #totalFuel = 0;
select
s.odometer,
format(fuel, 3) fuel,
s.distance,
format( distance / fuel, 2) as mpg
from (
select
partial_fillup as partial,
odometer,
(fuel+#totalFuel) as fuel,
#totalFuel as totalFuel,
#oldOdometer oldOdometer,
if ( partial_fillup, null,odometer - #oldOdometer ) as distance,
#totalFuel := if ( partial_fillup, #totalFuel + fuel, 0) as pastFuel,
#oldOdometer := if (partial_fillup,#oldOdometer,odometer ) as runningOdometer
from
fuel
order by
odometer ) s
where s.distance is not null
order by s.odometer
limit 1,999;
limit 1,999 simply there to skip the first row returned, since there is not enough data to calculate distance or mpg. On my copy of MySQL, doing this means you do not need to initialize the two variables (you don't have to include the set commands at the beginning), so it works with my reporting tool very well. If you do initialize them, you do not need the limit statement. Works assuming you don't have more than 999 rows returned.

Mysql copy points with srid 0 to srid 4326

I am trying to copy points with srid 0 from a table to another table with points srid 4326.
INSERT INTO `GeopositionAddresses2`(`Point`)
SELECT
ST_POINTFROMTEXT(
CONCAT(
'POINT(',
ST_X(`Point`),
' ',
ST_Y(`Point`),
')'
),
4326
) AS `Point`
FROM
`GeopositionAddresses`
Mysql return
#3617 - Latitude 142.730815 is out of range in function st_pointfromtext. It must be within [-90.000000, 90.000000].
and swapping these parameters returns the same error
...
'POINT(',
ST_Y(`Point`),
' ',
ST_X(`Point`),
')
...
The table GeopositionAddresses has such data:
ST_X(Point)
ST_Y(Point)
50.570907
36.571189
59.427922619334
24.619404439605
46.980327
142.730815
GeopositionAddreses table:
CREATE TABLE `GeopositionAddresses` (
`Point` point NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
GeopositionAddreses2 table:
CREATE TABLE `GeopositionAddresses` (
`Point` point NOT NULL SRID 4326
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
DBFiddle example error:
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=c9e64796dd84c4a07a1f2baac7f2f125
Latitude is -90 until 90, while longitude is -180 until 180.
Directly on the opposite side of the earth from the prime meridian is located the 180 meridian. This is the highest longitude possible.
and
Since the equator is 0 , the latitude of the north pole, 1/4 of the way around the globe going in a northerly direction, would be 90 N. This is the highest latitude possible.
http://www.jsu.edu/dept/geography/mhill/phygeogone/latlngprf.html
Seeing your data, Y must be the longitude.
X = Longitude, Y = Latitude
since in your data there is: Y=142.730815 AND range of latitude is -90 until 90, of course it generated error
here is my fiddle to show no error on reproducing your example: https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=ec568ec25dfc15078b523226d382304f
I also copy pasted your fiddle and switched X and Y in the INSERT INTO ... SELECT statement, and it worked: https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=ec568ec25dfc15078b523226d382304f

mysql select latitude longitude distance radius

I have two table
First one is "tbl1"
ID fullName mobile
1 Aaaa 1234567890
2 Bbbb 9874563210
3 Cccc 1237894560
Second is "tbl2"
ID lalitude longtitude currentTime
2 26.90884600 75.79238500 2016-06-02 13:32:25
2 26.90884600 75.79238500 2016-06-02 13:32:25
1 26.90884600 75.79238500 2016-06-02 13:32:25
I have input ID = 2 and lalitude= 28.654490 and longtitude = 77.267117 and distance = 5 kilometer.
I would like to get the list of users who are inside 5 kilometer distance from the point lalitude(28.654490) and longtitude(77.267117) from tbl2 with join tbl1 table.
I am new to the geo based information.
I am using MySQL.
Either you use MySQL's spatial extensions and convert your lat / long columns into a POINT and use st_distance() function to calculate the distance between 2 points.
Or you calculate the distances yourself using lat / long values stored as floating point numbers. For a solution see mySQL longitude and latitude query for other rows within x mile radius topic here on SO. The accepted answer indicates how to calculate the distance in km.
here is my solution
DELIMITER ;;
CREATE PROCEDURE proc_getUsersByDistance(in _ID int, in _lat decimal(10,7), in _long decimal(10,7), in _distance int)
BEGIN
Declare _radius decimal(10,5);
Declare _lng_min decimal(10,7);
Declare _lng_max decimal(10,7);
Declare _lat_min decimal(10,7);
Declare _lat_max decimal(10,7);
set _radius=_distance*0.621371;
set _lng_min = _long - _radius/abs(cos(radians(_lat))*69);
set _lng_max = _long + _radius/abs(cos(radians(_lat))*69);
set _lat_min = _lat - (_radius/69);
set _lat_max = _lat + (_radius/69);
SELECT tbl1.*, tbl2.latitude, tbl2.longitude,tbl2.currentTime
from tbl1 INNER JOIN tbl2 on tbl1.ID=tbl2.ID
where tbl2.ID=_ID and ((tbl2.latitude between _lat_min and _lat_max) and (tbl2.longitude between _lng_min AND _lng_max))
order by tbl2.currentTime;
END

Mysql Order By Problematic

Okay, I'm having some difficulties with order by. Here is the problem I need to solve:
In the database I have written every tile of a map, that is 101 x 101 big. The table has 3 columns(ID, x, y), now I gotta select all the tiles in some radious. For example, I used this query:
SELECT *
FROM tile
WHERE ((x >= -3 AND x <= 3)
AND (y >= -3 AND y <= 3))
ORDER BY x ASC, y DESC;
This query selects all tiles in radius of 3 of the given coordinate (0|0) for now.
But, it doesn't sort them the way I want it to. Basically, the output must be like this.
But this is the closest I got.
http://prntscr.com/zqjd7
Edit:
Disregard the double values, had double inputs for each coordinate. Haven't seen it.
It seems that your problem is around the ASC / DESC modificator.
But since we're here, wouldn't you prefer to use a distance formula? Something near
SELECT x, y FROM tile WHERE
(
POW(x-#var1, 2) + POW(y-#var2, 2) <= POW(3, 2)
)
ORDER BY x DESC, y ASC;
Here, given a point P (m,n), we shall know the distance to a fixed point Q (x,y) by acerting D(P,Q) = SQRT( (x-m)² + (y-n)² ). As much as it has to be less than (or equals) your desired radius (= 3), we have so SQRT( (x-m)² + (y-n)² ) <= 3, or better, (x-m)² + (y-n)² <= 3², raising both terms to its square power.
SQL-language speaking, we write POW(x-m, 2) + POW(y-n, 2) <= POW(3, 2), willing to say that the distance between (x,y) and (m,n) is last than or equal 3.
About #var, it's where you enter your input value. More specifically, they are session variables, but you don't really want to use it to perform a select; just substitute them by any number you want, e.g. you can choose the origin (0,0) by putting 0 on place of #var1 and #var2.
[Update]
Well... It's always a good idea to test your code before answering. In fact I should have suggested to order firstly by y, since we first care about ordering rows to display on screen. The following code was (finally) tested (on test DB); my last suggest is to create the following index (index_y_x):
USE `test` ;
CREATE TABLE IF NOT EXISTS `test`.`tile` (
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT ,
`x` INT(11) NULL DEFAULT 0 ,
`y` INT(11) NULL DEFAULT 0 ,
PRIMARY KEY (`id`) ,
INDEX `index_y_x` (`y` DESC, `x` ASC) )
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;
INSERT tile (x,y) VALUES
(-2,-2),(-2, -1),(-2, 0),(-2, 1),(-2, 2),
(-1,-2),(-1, -1),(-1, 0),(-1, 1),(-1, 2),
(0,-2), (0, -1), (0, 0), (0, 1), (0, 2),
(1,-2), (1, -1), (1, 0), (1, 1), (1, 2),
(2,-2), (2, -1), (2, 0), (2, 1), (2, 2);
SELECT x, y FROM tile
WHERE POW(x-3, 2) + POW(y-3, 2) <= POW(3, 2)
ORDER BY y DESC, x ASC;
This returns items near the point (3,3), in a range of 3 units

Why use the SQL Server 2008 geography data type?

I am redesigning a customer database and one of the new pieces of information I would like to store along with the standard address fields (Street, City, etc.) is the geographic location of the address. The only use case I have in mind is to allow users to map the coordinates on Google maps when the address cannot otherwise be found, which often happens when the area is newly developed, or is in a remote/rural location.
My first inclination was to store latitude and longitude as decimal values, but then I remembered that SQL Server 2008 R2 has a geography data type. I have absolutely no experience using geography, and from my initial research, it looks to be overkill for my scenario.
For example, to work with latitude and longitude stored as decimal(7,4), I can do this:
insert into Geotest(Latitude, Longitude) values (47.6475, -122.1393)
select Latitude, Longitude from Geotest
but with geography, I would do this:
insert into Geotest(Geolocation) values (geography::Point(47.6475, -122.1393, 4326))
select Geolocation.Lat, Geolocation.Long from Geotest
Although it's not that much more complicated, why add complexity if I don't have to?
Before I abandon the idea of using geography, is there anything I should consider? Would it be faster to search for a location using a spatial index vs. indexing the Latitude and Longitude fields? Are there advantages to using geography that I am not aware of? Or, on the flip side, are there caveats that I should know about which would discourage me from using geography?
Update
#Erik Philips brought up the ability to do proximity searches with geography, which is very cool.
On the other hand, a quick test is showing that a simple select to get the latitude and longitude is significantly slower when using geography (details below). , and a comment on the accepted answer to another SO question on geography has me leery:
#SaphuA You're welcome. As a sidenote be VERY carefull of using a
spatial index on a nullable GEOGRAPHY datatype column. There are some
serious performance issue, so make that GEOGRAPHY column non-nullable
even if you have to remodel your schema. – Tomas Jun 18 at 11:18
All in all, weighing the likelihood of doing proximity searches vs. the trade-off in performance and complexity, I've decided to forgo the use of geography in this case.
Details of the test I ran:
I created two tables, one using geography and another using decimal(9,6) for latitude and longitude:
CREATE TABLE [dbo].[GeographyTest]
(
[RowId] [int] IDENTITY(1,1) NOT NULL,
[Location] [geography] NOT NULL,
CONSTRAINT [PK_GeographyTest] PRIMARY KEY CLUSTERED ( [RowId] ASC )
)
CREATE TABLE [dbo].[LatLongTest]
(
[RowId] [int] IDENTITY(1,1) NOT NULL,
[Latitude] [decimal](9, 6) NULL,
[Longitude] [decimal](9, 6) NULL,
CONSTRAINT [PK_LatLongTest] PRIMARY KEY CLUSTERED ([RowId] ASC)
)
and inserted a single row using the same latitude and longitude values into each table:
insert into GeographyTest(Location) values (geography::Point(47.6475, -122.1393, 4326))
insert into LatLongTest(Latitude, Longitude) values (47.6475, -122.1393)
Finally, running the following code shows that, on my machine, selecting the latitude and longitude is approximately 5 times slower when using geography.
declare #lat float, #long float,
#d datetime2, #repCount int, #trialCount int,
#geographyDuration int, #latlongDuration int,
#trials int = 3, #reps int = 100000
create table #results
(
GeographyDuration int,
LatLongDuration int
)
set #trialCount = 0
while #trialCount < #trials
begin
set #repCount = 0
set #d = sysdatetime()
while #repCount < #reps
begin
select #lat = Location.Lat, #long = Location.Long from GeographyTest where RowId = 1
set #repCount = #repCount + 1
end
set #geographyDuration = datediff(ms, #d, sysdatetime())
set #repCount = 0
set #d = sysdatetime()
while #repCount < #reps
begin
select #lat = Latitude, #long = Longitude from LatLongTest where RowId = 1
set #repCount = #repCount + 1
end
set #latlongDuration = datediff(ms, #d, sysdatetime())
insert into #results values(#geographyDuration, #latlongDuration)
set #trialCount = #trialCount + 1
end
select *
from #results
select avg(GeographyDuration) as AvgGeographyDuration, avg(LatLongDuration) as AvgLatLongDuration
from #results
drop table #results
Results:
GeographyDuration LatLongDuration
----------------- ---------------
5146 1020
5143 1016
5169 1030
AvgGeographyDuration AvgLatLongDuration
-------------------- ------------------
5152 1022
What was more surprising is that even when no rows are selected, for example selecting where RowId = 2, which doesn't exist, geography was still slower:
GeographyDuration LatLongDuration
----------------- ---------------
1607 948
1610 946
1607 947
AvgGeographyDuration AvgLatLongDuration
-------------------- ------------------
1608 947
If you plan on doing any spatial computation, EF 5.0 allows LINQ Expressions like:
private Facility GetNearestFacilityToJobsite(DbGeography jobsite)
{
var q1 = from f in context.Facilities
let distance = f.Geocode.Distance(jobsite)
where distance < 500 * 1609.344
orderby distance
select f;
return q1.FirstOrDefault();
}
Then there is a very good reason to use Geography.
Explanation of spatial within Entity Framework.
Updated with Creating High Performance Spatial Databases
As I noted on Noel Abrahams Answer:
A note on space, each coordinate is stored as a double-precision floating-point number that is 64 bits (8 bytes) long, and 8-byte binary value is roughly equivalent to 15 digits of decimal precision, so comparing a decimal(9,6) which is only 5 bytes, isn't exactly a fair comparison. Decimal would have to be a minimum of Decimal(15,12) (9 bytes) for each LatLong (total of 18 bytes) for a real comparison.
So comparing storage types:
CREATE TABLE dbo.Geo
(
geo geography
)
GO
CREATE TABLE dbo.LatLng
(
lat decimal(15, 12),
lng decimal(15, 12)
)
GO
INSERT dbo.Geo
SELECT geography::Point(12.3456789012345, 12.3456789012345, 4326)
UNION ALL
SELECT geography::Point(87.6543210987654, 87.6543210987654, 4326)
GO 10000
INSERT dbo.LatLng
SELECT 12.3456789012345, 12.3456789012345
UNION
SELECT 87.6543210987654, 87.6543210987654
GO 10000
EXEC sp_spaceused 'dbo.Geo'
EXEC sp_spaceused 'dbo.LatLng'
Result:
name rows data
Geo 20000 728 KB
LatLon 20000 560 KB
The geography data-type takes up 30% more space.
Additionally the geography datatype is not limited to only storing a Point, you can also store LineString, CircularString, CompoundCurve, Polygon, CurvePolygon, GeometryCollection, MultiPoint, MultiLineString, and MultiPolygon and more. Any attempt to store even the simplest of Geography types (as Lat/Long) beyond a Point (for example LINESTRING(1 1, 2 2) instance) will incur additional rows for each point, a column for sequencing for the order of each point and another column for grouping of lines. SQL Server also has methods for the Geography data types which include calculating Area, Boundary, Length, Distances, and more.
It seems unwise to store Latitude and Longitude as Decimal in Sql Server.
Update 2
If you plan on doing any calculations like distance, area, etc, properly calculating these over the surface of the earth is difficult. Each Geography type stored in SQL Server is also stored with a Spatial Reference ID. These id's can be of different spheres (the earth is 4326). This means that the calculations in SQL Server will actually calculate correctly over the surface of the earth (instead of as-the-crow-flies which could be through the surface of the earth).
Another thing to consider is the storage space taken up by each method. The geography type is stored as a VARBINARY(MAX). Try running this script:
CREATE TABLE dbo.Geo
(
geo geography
)
GO
CREATE TABLE dbo.LatLon
(
lat decimal(9, 6)
, lon decimal(9, 6)
)
GO
INSERT dbo.Geo
SELECT geography::Point(36.204824, 138.252924, 4326) UNION ALL
SELECT geography::Point(51.5220066, -0.0717512, 4326)
GO 10000
INSERT dbo.LatLon
SELECT 36.204824, 138.252924 UNION
SELECT 51.5220066, -0.0717512
GO 10000
EXEC sp_spaceused 'dbo.Geo'
EXEC sp_spaceused 'dbo.LatLon'
Result:
name rows data
Geo 20000 728 KB
LatLon 20000 400 KB
The geography data-type takes up almost twice as much space.
CREATE FUNCTION [dbo].[fn_GreatCircleDistance]
(#Latitude1 As Decimal(38, 19), #Longitude1 As Decimal(38, 19),
#Latitude2 As Decimal(38, 19), #Longitude2 As Decimal(38, 19),
#ValuesAsDecimalDegrees As bit = 1,
#ResultAsMiles As bit = 0)
RETURNS decimal(38,19)
AS
BEGIN
-- Declare the return variable here
DECLARE #ResultVar decimal(38,19)
-- Add the T-SQL statements to compute the return value here
/*
Credit for conversion algorithm to Chip Pearson
Web Page: www.cpearson.com/excel/latlong.aspx
Email: chip#cpearson.com
Phone: (816) 214-6957 USA Central Time (-6:00 UTC)
Between 9:00 AM and 7:00 PM
Ported to Transact SQL by Paul Burrows BCIS
*/
DECLARE #C_RADIUS_EARTH_KM As Decimal(38, 19)
SET #C_RADIUS_EARTH_KM = 6370.97327862
DECLARE #C_RADIUS_EARTH_MI As Decimal(38, 19)
SET #C_RADIUS_EARTH_MI = 3958.73926185
DECLARE #C_PI As Decimal(38, 19)
SET #C_PI = pi()
DECLARE #Lat1 As Decimal(38, 19)
DECLARE #Lat2 As Decimal(38, 19)
DECLARE #Long1 As Decimal(38, 19)
DECLARE #Long2 As Decimal(38, 19)
DECLARE #X As bigint
DECLARE #Delta As Decimal(38, 19)
If #ValuesAsDecimalDegrees = 1
Begin
set #X = 1
END
Else
Begin
set #X = 24
End
-- convert to decimal degrees
set #Lat1 = #Latitude1 * #X
set #Long1 = #Longitude1 * #X
set #Lat2 = #Latitude2 * #X
set #Long2 = #Longitude2 * #X
-- convert to radians: radians = (degrees/180) * PI
set #Lat1 = (#Lat1 / 180) * #C_PI
set #Lat2 = (#Lat2 / 180) * #C_PI
set #Long1 = (#Long1 / 180) * #C_PI
set #Long2 = (#Long2 / 180) * #C_PI
-- get the central spherical angle
set #Delta = ((2 * ASin(Sqrt((power(Sin((#Lat1 - #Lat2) / 2) ,2)) +
Cos(#Lat1) * Cos(#Lat2) * (power(Sin((#Long1 - #Long2) / 2) ,2))))))
If #ResultAsMiles = 1
Begin
set #ResultVar = #Delta * #C_RADIUS_EARTH_MI
End
Else
Begin
set #ResultVar = #Delta * #C_RADIUS_EARTH_KM
End
-- Return the result of the function
RETURN #ResultVar
END