MySQL Function for calculating Haversine Distance - mysql

all.
I want to create a mysql function that calculates the haversine distance between two geo-code.
CREATE FUNCTION haversineDistance
(
lat1 VARCHAR(256),
long1 VARCHAR(256),
lat2 VARCHAR(256),
long2 VARCHAR(256)
)
RETURNS FLOAT DETERMINISTIC
BEGIN
DECLARE radLat1 FLOAT;
DECLARE radLong1 FLOAT;
DECLARE radLat2 FLOAT;
DECLARE radLong2 FLOAT;
DECLARE dLat FLOAT;
DECLARE dLong FLOAT;
DECLARE cordLength FLOAT;
DECLARE centralAngle FLOAT;
DECLARE distance FLOAT;
SET radLat1 = CAST(lat1 AS FLOAT) * PI() / 180;
SET radLong1 = CAST(long1 AS FLOAT) * PI() / 180;
SET radLat2 = CAST(lat2 AS FLOAT) * PI() / 180;
SET radLong2 = CAST(long2 AS FLOAT) * PI() / 180;
SET dLat = radLat2 - radLat1;
SET dLong = radLong2 - radLong2;
SET cordLength = POW(SIN(dLat/2),2)+COS(lat1)*COS(lat2)*POW(SIN(dLon/2),2);
SET centralAngle = 2 * ATAN2(SQRT(cordLength), SQRT(1-cordLength));
SET distance = 6367 * centralAngle;
RETURN distance;
END
But I got an error like this;
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 '' at line 4
Anyone has an idea?
Thank you in advance.

Okay.
Solved it.
DELIMITER $$
CREATE FUNCTION haversineDistance
(
lat1 VARCHAR(256),
long1 VARCHAR(256),
lat2 VARCHAR(256),
long2 VARCHAR(256))
RETURNS FLOAT DETERMINISTIC
BEGIN
DECLARE radLat1 FLOAT;
DECLARE radLong1 FLOAT;
DECLARE radLat2 FLOAT;
DECLARE radLong2 FLOAT;
DECLARE dLat FLOAT;
DECLARE dLong FLOAT;
DECLARE cordLength FLOAT;
DECLARE centralAngle FLOAT;
DECLARE distance FLOAT;
SET radLat1 = CAST(lat1 AS DECIMAL(10,10)) * PI() / 180;
SET radLong1 = CAST(long1 AS DECIMAL(10,10)) * PI() / 180;
SET radLat2 = CAST(lat2 AS DECIMAL(10,10)) * PI() / 180;
SET radLong2 = CAST(long2 AS DECIMAL(10,10)) * PI() / 180;
SET dLat = radLat2 - radLat1;
SET dLong = radLong2 - radLong2;
SET cordLength = POW(SIN(dLat/2),2)+COS(lat1)*COS(lat2)*POW(SIN(dLon/2),2);
SET centralAngle = 2 * ATAN2(SQRT(cordLength), SQRT(1-cordLength));
SET distance = 6367 * centralAngle;
RETURN distance;
END

Right now, you're getting an error, due to the semi-colon characters present as line delimiter in your function.
To explain it further, directly quoting from MySQL documentation
By default, mysql recognizes the semicolon as a statement delimiter,
so you must redefine the delimiter temporarily to cause mysql to pass
the entire stored program definition to the server.
This means that you must override the default delimiter temporarily for your program to compile. Enacapsulate your program between
DELIMITER $$
your code for function
$$
and then give it a try.
EDIT:
You can change back the delimiter by specifying the default delimiter again
mysql> DELIMITER ;

Related

Multiple select statements in same function

I have the following function:
DELIMITER $$
create function fp_v2.fp_splitadjprice (id char(8), startdate date)
returns float
begin
declare splitfactor float;
declare splitadjprice float;
declare spinofffactor float;
set splitfactor = 1.0;
select splitfactor = fp_v2.fp_splitfactor_prices(id, startdate);
select splitadjprice = convert(float,p_price * splitfactor)
from fp_v2.fp_basic_prices p
where fsym_id = id and p_date = startdate;
return splitadjprice;
END$$
DELIMITER ;
I get an error message at the 2nd select statement saying "expected a ( or with".
I really don't understand the syntax of MySQL workbench. It seems pretty random to me. Like when should I put ; and when should I not?. What are the rules?
You need use SELECT .. INTO to update your variables.
convert sintaxis is CONVERT(value, type) and you cant use FLOAT as type need use DECIMAL and you probably dont need it anyway because your both variable are float already.
DELIMITER $$
create function fp_v2.fp_splitadjprice (id char(8), startdate date)
returns float
begin
declare splitfactor float;
declare splitadjprice float;
declare spinofffactor float;
set splitfactor = 1.0;
SELECT fp_v2.fp_splitfactor_prices(id, startdate) INTO splitfactor ;
SELECT convert(p_price * splitfactor, DECIMAL (10,4) INTO splitadjprice
FROM fp_v2.fp_basic_prices p
WHERE fsym_id = id and p_date = startdate;
return splitadjprice;
END$$
DELIMITER ;

convert TSQL query to MySQL

I need to convert this tSQL query into MySQL query version 5.7.14
I tried declare parameter with the following syntax
declare #commissionType INT;
but I reached a dead end and need help to convert this query
CREATE PROCEDURE MyProc
#chainId int
as
BEGIN
declare #commissionMethod int
declare #commissionType int
declare #value decimal(18,2)
set #commissionMethod = 1
set #value = 200000
set #commissionType = (select CommissionType from CommissionRules
where ChainId = #chainId )
IF(#commissionMethod = 1)
BEGIN
print('alert')
select (Fixed * #value) / 100 from CommissionRules where ChainId = #chainId
END
END
This is pretty much a literal conversion. But check your logic. It doesn't make any sense. v_commissionMethod is always 1 and v_commissionType is not even being used after selecting a value.
DELIMITER //
CREATE PROCEDURE MyProc (
p_chainId int)
BEGIN
declare v_commissionMethod int;
declare v_commissionType int;
declare v_value decimal(18,2);
set v_commissionMethod = 1;
set v_value = 200000;
select CommissionType into v_commissionType from CommissionRules
where ChainId = p_chainId ;
IF(v_commissionMethod = 1)
THEN
/* print('alert') */
select (Fixed * v_value) / 100 from CommissionRules where ChainId = p_chainId;
END IF;
END;
//
DELIMITER ;
Something like this:
DELIMITER $$
CREATE PROCEDURE MyProc (
in_chainId unsigned
) as
BEGIN
select v_CommissionType := CommissionType,
v_commissionMethod = 1,
v_value = 200000
from CommissionRules
where ChainId = in_chainId;
if v_commissionMethod = 1 then
select 'alert';
select (Fixed * v_value) / 100
from CommissionRules
where ChainId = in_chainId
end if;
END;$$
DELIMITER ;

MySQL: Creating regr_slope function

In MySQL I have added this function to calculate slope:
DELIMITER $$
CREATE FUNCTION regr_slope(x float, y float)
RETURNS float
DETERMINISTIC
BEGIN
DECLARE n int;
DECLARE sum_x float;
DECLARE sum_y float;
DECLARE sum_xx float;
DECLARE sum_xy float;
DECLARE slope float;
SET n = COUNT(x);
SET sum_x = SUM(x);
SET sum_y = SUM(y);
SET sum_xx = SUM(x*x);
SET sum_xy = SUM(x*y);
SET slope = (n * sum_xy - sum_x * sum_y) / (n * sum_xx - POWER(sum_x, 2));
RETURN slope;
END$$
DELIMITER ;
However, when I use it like this:
SELECT regr_slope(pd.avg_velocity, pd.load_kg) FROM push_data
I get the error Invalid use of group function.
What could be the reason for this?

Calculating distance from latlang --MySQL functional error (#1064)

I am creating a function for calculating the haversian distance but in i am getting the Mysql syntax 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 '' at line 8
DELIMITER $$
CREATE FUNCTION GEODIST (lat1 DOUBLE, lon1 DOUBLE, lat2 DOUBLE, lon2 DOUBLE)
RETURNS DOUBLE
DETERMINISTIC
BEGIN
DECLARE dist DOUBLE;
SET dist = round(acos(cos(radians(lat1)) * cos(radians(lon1)) * cos(radians(lat2)) * cos(radians(lon2)) + cos(radians(lat1)) * sin(radians(lon1)) * cos(radians(lat2)) * sin(radians(lon2)) + sin(radians(lat1)) * sin(radians(lat2))) * 6378.8, 1);
RETURN dist;
END$$
I have tried your code in Mysql,and the same didn't work ;
but instead when I added an extra line it worked,
which was resetting the delimiter again
Kindly check
END$$
DELIMITER ;
And sorry in case if this also goes wrong..But worked fine for me

JDBC insert statement don't start triggers and functions on MySQL

I have a Trigger and a Function as given below
Trigger:
DELIMITER $$
USE `server`$$
DROP TRIGGER /*!50032 IF EXISTS */ `calcQumilative`$$
CREATE
/*!50017 DEFINER = 'root'#'%' */
TRIGGER `calcQumilative` BEFORE INSERT ON `cpdata`
FOR EACH ROW BEGIN
DECLARE curr_distance DECIMAL(12,4) DEFAULT 0;
DECLARE prev_id INT;
DECLARE prev_lat DECIMAL(12,7);
DECLARE prev_lon DECIMAL(12,7);
DECLARE prev_idling INT;
DECLARE prev_idlingcount INT;
DECLARE prev_ignition INT;
DECLARE prev_ignitioncount INT;
DECLARE prev_fuelconsumption DECIMAL(12,4);
DECLARE prev_dist DECIMAL(12,4);
DECLARE prev_infuel DECIMAL(12,4);
DECLARE prev_outfuel DECIMAL(12,4);
DECLARE prev_hw_infuel DECIMAL(12,4);
DECLARE prev_hw_outfuel DECIMAL(12,4);
DECLARE prev_tmp_idl_fuel DECIMAL(12,4) DEFAULT 0;
DECLARE curr_idling INT;
DECLARE curr_idlingcount INT DEFAULT 0;
DECLARE curr_ignition INT;
DECLARE curr_ignitioncount INT;
DECLARE curr_fuelconsumption DECIMAL(12,4);
DECLARE curr_idl_fuelconsumption DECIMAL(12,4)DEFAULT 0;
DECLARE curr_tmp_idl_fuel DECIMAL(12,4) DEFAULT 0;
DECLARE curr_infuel DECIMAL(12,4);
DECLARE curr_outfuel DECIMAL(12,4);
DECLARE temprowcount INT DEFAULT 1 ;
SELECT id,latitude ,longitude,idling,idlingcount,ignition,ignitioncount,idlingfuelconsumption,distance,infuel_pulsecount,
outfuel_pulsecount,hw_infuel_pulsecount,hw_outfuel_pulsecount,tmp_idlingfuelconsumption INTO
prev_id,prev_lat,prev_lon,prev_idling,prev_idlingcount,prev_ignition,prev_ignitioncount,prev_fuelconsumption,prev_dist,prev_infuel,
prev_outfuel,prev_hw_infuel,prev_hw_outfuel,prev_tmp_idl_fuel FROM carbonpoddata AS prevrow
WHERE prevrow.id < NEW.id AND NEW.vehicalnum = prevrow.vehicalnum AND DATE (NEW.podtimestamp) = DATE(prevrow.podtimestamp) ORDER BY podtimestamp DESC LIMIT 1;
IF prev_id IS NOT NULL THEN
IF NEW.hw_infuel_pulsecount > prev_hw_infuel THEN
SET curr_infuel = prev_infuel + (NEW.hw_infuel_pulsecount - prev_hw_infuel) ;
ELSE
SET curr_infuel = prev_infuel + (100- prev_hw_infuel) + NEW.hw_infuel_pulsecount ;
END IF;
IF NEW.hw_outfuel_pulsecount > prev_hw_outfuel THEN
SET curr_outfuel = prev_outfuel + (NEW.hw_outfuel_pulsecount - prev_hw_outfuel) ;
ELSE
SET curr_outfuel = prev_outfuel + (100- prev_hw_outfuel) + NEW.hw_outfuel_pulsecount ;
END IF;
IF prev_ignition = NEW.ignition THEN
SET curr_ignitioncount = (prev_ignitioncount+1);
ELSE
SET curr_ignitioncount = 1;
END IF;
IF ( prev_lat = NEW.latitude AND prev_lon = NEW.longitude AND NEW.ignition = 1) THEN
SET curr_idling = 1;
IF prev_idling = curr_idling THEN
SET curr_idlingcount = prev_idlingcount+1 ;
SET curr_fuelconsumption = prev_tmp_idl_fuel + (((curr_infuel - curr_outfuel)* 5) /1000 ) ;
IF curr_idlingcount = 10 THEN
SET curr_idl_fuelconsumption = curr_fuelconsumption;
ELSE
IF curr_idlingcount > 10 THEN
SET curr_idl_fuelconsumption = (((curr_infuel - curr_outfuel)* 5) /1000 ) ;
ELSE
SET curr_tmp_idl_fuel = curr_fuelconsumption;
END IF;
END IF;
ELSE
SET curr_idlingcount = 1;
END IF;
ELSE
SET curr_idling = 0;
IF prev_idling = curr_idling THEN
SET curr_idlingcount = prev_idlingcount+1 ;
ELSE
SET curr_idlingcount = 1;
END IF;
END IF;
SELECT CALCULATE_DISTANCE(prev_lat,prev_lon,NEW.latitude,NEW.longitude) INTO curr_distance;
IF curr_distance IS NULL THEN
SET curr_distance = 0;
END IF;
SET curr_distance = curr_distance + prev_dist;
SET NEW.distance = curr_distance;
SET NEW.ignitioncount =curr_ignitioncount ;
SET NEW.idlingcount =curr_idlingcount;
SET NEW.idling = curr_idling;
SET NEW.infuel_pulsecount = curr_infuel;
SET NEW.outfuel_pulsecount = curr_outfuel;
SET NEW.tmp_idlingfuelconsumption = curr_tmp_idl_fuel;
SET NEW.idlingfuelconsumption = curr_idl_fuelconsumption;
END IF;
END;
$$
DELIMITER ;
Above trigger has a call to function CALCULATE_DISTANCE:
DELIMITER $$
USE `server`$$
DROP FUNCTION IF EXISTS `CALCULATE_DISTANCE`$$
CREATE DEFINER=`root`#`%` FUNCTION `CALCULATE_DISTANCE`(`#oLat` DECIMAL(10,7), `#oLon` DECIMAL(10,7), `#dLat` DECIMAL(10,7), `#dLon` DECIMAL(10,7)) RETURNS DECIMAL(10,7)
NO SQL
BEGIN
RETURN (
(
ACOS(
SIN(`#dLat` * PI() / 180) *
SIN(`#oLat` * PI() / 180) +
COS(`#dLat` * PI() / 180) *
COS(`#oLat` * PI() / 180) *
COS((`#dLon` - `#oLon`) * PI() / 180)
) *
180 / PI()
) *
60 *
1.1515 *
1.609344
);
END$$
DELIMITER ;
When I insert a record into cpdata table it was supposed to start trigger before insert, but it looks like MySQL didn't recognize the same when I used both Hibernate and JDBC to insert a record.
But the trigger works properly if I insert multiple records using SQLYog. What could be the cause and how can I solve it?
I have exactly the same problem. I have found the cause of it, but not the cure.
When a connection eventually are fetched from the DriverManager.getConnection(), the following is automatically executed by the MySQL JDBC Connection:
SET sql_mode='STRICT_TRANS_TABLES'
I have not found a way to disable it yet. One solution would be to execute this before you execute any SQL
SET sql_mode=''
But this is probably not easy in a ORM framework as Hibernate.