Getting syntax errors when creating function - mysql

I have been spending over 2 hours now trying to google my way to the answer.
I am completely new to SQL and MySQL and I have tried to write the following function:
CREATE FUNCTION fp_spinofffactor (id char(8), startdate date)
RETURNS float
BEGIN
DECLARE spinoffFactor float; (ERROR- EXPECTED A ";")
select spinoffFactor = ISNULL(EXP(SUM(LOG(spinoffFactor))),1)
from(
select case when (prev_price- divs) <= 0 THEN 1
else (prev_price- divs)/prev_price end as spinoffFactor
from (select
divs,
fp_v2.fp_prevUnadjPrice(id, ex_date) as prev_price
from (
select sum(fbd.p_divs_pd) as divs,fbd.p_divs_exdate as ex_date
from fp_v2.fp_basic_dividends fbd
where fbd.fsym_id = id
and fbd.p_divs_s_pd=1
and fbd.p_divs_exdate > startdate
group by fbd.p_divs_exdate ) a ) b ) c;
return spinofffactor; ERROR (Return is not valid at this position)
END ERROR (END IS NOT VALID AT THIS position)
But I get multiple syntax errors. I have written the errors where I get them.
I have a hard time finding information about the syntax rules of MySQL and the workbench.
Can anyone help ?

You need to provide delimiter in MySql workbench to tell where your code begins and ends.
Assuming your syntax is correct, you can write as below.
DELIMITER $$
CREATE FUNCTION fp_spinofffactor (id char(8), startdate date)
RETURNS float
BEGIN
DECLARE spinoffFactor float;
select spinoffFactor = ISNULL(EXP(SUM(LOG(spinoffFactor))),1)
from(
select case when (prev_price- divs) <= 0 THEN 1
else (prev_price- divs)/prev_price end as spinoffFactor
from (select
divs,
fp_v2.fp_prevUnadjPrice(id, ex_date) as prev_price
from (
select sum(fbd.p_divs_pd) as divs,fbd.p_divs_exdate as ex_date
from fp_v2.fp_basic_dividends fbd
where fbd.fsym_id = id
and fbd.p_divs_s_pd=1
and fbd.p_divs_exdate > startdate
group by fbd.p_divs_exdate ) a ) b ) c;
return spinofffactor;
END$$
DELIMITER ;
You can also, run this from MySQL command prompt and it should work.

Related

How to return boolean based on number of records in database?

Here's what I've tried. My host is returning an error, "Sorry an unexpected error happened!" .
I want it to return true if there is at least 1 record with combination pdriver_id, ptruck_number, and pdate.
DELIMITER %%
CREATE FUNCTION DriverActiveInTruckByDate(
pdriver_id INT,
ptruck_number INT,
pdate DATETIME
)
RETURNS boolean
DETERMINISTIC
BEGIN
DECLARE inDB INT DEFAULT 0;
SET inDB =
SELECT IF(COUNT(*) >= 1,1,0)
FROM
truck_timeline tl
WHERE 1=1
AND tl.driver_id = pdriver_id
AND tl.truck_number = ptruck_number
AND ((pdate BETWEEN tl.begin_date AND tl.end_date) OR (pdate >= tl.begin_date AND tl.end_date IS NULL))
END
%%
DELIMITER ;
Several fixes are needed:
The function is not DETERMINISTIC. This means the result will always be the same given the same inputs. In your case, the result may be different depending on the data in your truck_timeline table. So I would suggest using READS SQL DATA.
If you use SET variable = SELECT... you must put the SELECT in a subquery:
SET inDB = (SELECT ...);
The current manual recommends using SELECT ... INTO variable instead of SET. See https://dev.mysql.com/doc/refman/8.0/en/select-into.html
The INTO position at the end of the statement is supported as of MySQL 8.0.20, and is the preferred position.
SELECT ... INTO inDB;
The function you show doesn't have a RETURN statement. See https://dev.mysql.com/doc/refman/8.0/en/return.html
There must be at least one RETURN statement in a stored function.
Your Full Code could be like this:
DELIMITER %%
CREATE FUNCTION DriverActiveInTruckByDate(
pdriver_id INT,
ptruck_number INT,
pdate DATETIME
)
RETURNS boolean
DETERMINISTIC
BEGIN
DECLARE inDB INT DEFAULT 0;
SET inDB =
(SELECT IF(COUNT(*) >= 1,1,0)
FROM
truck_timeline tl
WHERE 1=1
AND tl.driver_id = pdriver_id
AND tl.truck_number = ptruck_number
AND ((pdate BETWEEN tl.begin_date AND tl.end_date) OR (pdate >= tl.begin_date AND tl.end_date IS NULL))
);
END %%
DELIMITER ;

Invalid use of group function when using count() MySQL

I'm trying to get the average amount of orders per customer and I've tried a bunch of things but I can't find an answer that works to this particular problem.
With pretty much everything I've tried I get Error 1111: Invalid use of group function.
Results on google are only talking about not using where statements so I'm a little lost.
DELIMITER //
create function avgAmount()
returns double
BEGIN
DECLARE AvgAmountOfOrders double;
SET AvgAmountOfOrders = (COUNT(DISTINCT orderID) * 1.0) / NULLIF(COUNT(DISTINCT CustomerID), 0) ;
return AvgAmountOfOrders;
END;//
DELIMITER ;
Select avgAmount();
Thank you The Impaler.
For anyone interested this was the solution.
DELIMITER //
create function test123()
returns double
BEGIN
DECLARE AvgAmountOfOrders double;
SET AvgAmountOfOrders = (select COUNT(DISTINCT OrderID * 1.0) / NULLIF(COUNT(DISTINCT CustomerID), 0)from orders) ;
return AvgAmountOfOrders;
END;//
DELIMITER ;
Select test123();

Why does a MySql query, valid in Workbench, return syntax errors in phpmyadmin?

so i have 2 tables as table1 and table2 in 2 different databases as id_information and id_information_backup. Both the tables have the following columns: (id bigint, name varchar, surname varchar) I made this trigger where when the user enters name and surname in table1 , it calculates the ascii code of it and do some calculations and store it in the "name" column of the second table which is "table2". All of these has been done in Mysql workbench. when i import the code into phpmyadmin then it gives me too many syntax errors. I tried to figure what syntax errors do i have but i could not find. I am sharing the trigger below. Kindly help me if you can. I will really appreciate it. I guess it is because of the version that i used is MySQL workbench 8.0 and the version that i am importing this into is PHPmyadmin 4.9.4 . Fix the problem if you can please.
delimiter $$
CREATE DEFINER = CURRENT_USER TRIGGER `id_information`.`table1_after_INSERT1` AFTER INSERT ON `table1` FOR EACH ROW
BEGIN
declare p , r , copy, result, result1 decimal(64,0);
declare name1, surnam varchar(15);
declare a int;
set name1 = new.name;
set surnam = new.surname;
set a= 100;
set result =0;
set copy = 0;
set result1 =0;
set p =0 ;
set r =0 ;
with recursive cte as (
select name1 as name1, left(name1, 1) as val, 1 as idx
union all
select name1, substring(name1, idx + 1, 1), idx + 1
from cte
where idx < char_length(name1)
)
select group_concat(ascii(val) + a order by idx separator '') ascii_word from cte into result;
with recursive ctee as (
select surnam as surnam, left(surnam, 1) as vall , 1 as idxx
union all
select surnam, substring(surnam, idxx+ 1, 1), idxx+ 1
from ctee
where idxx< char_length(surnam)
)
select group_concat(ascii(vall ) + a order by idxx separator '') ascii_word from ctee into result1;
select group_concat(result, result1) into copy;
insert into id_information_backup.table2 set table2.name = copy;
END$$
delimiter ;
When you try to run the command (by pressing the "Go" button at the bottom of the SQL text area), what happens?
If phpMyAdmin is showing the errors as red circles with a white x to the left of the SQL area before submitting, then these are syntax warnings that won't affect your ability to submit the query. These are provided as hints by the SQL linter in phpMyAdmin.
phpMyAdmin syntax warning:
If the errors come after submitting the statements, then the errors come from MySQL itself and aren't directly caused by phpMyAdmin.
MySQL syntax error:
In PHPMyAdmin you need to set up delimiter in a small box under the main query
It should be signed as "Delimiter" ;-)
I ended getting caught by that one a few time :-D

Very slow execution when calling function

I have two functions. The second function uses the output from the first function.
One is:
DELIMITER $$
DROP FUNCTION IF EXISTS fp_splitfactor;
CREATE FUNCTION fp_splitfactor_price (id CHAR(8), startdate DATE)
RETURNS FLOAT
BEGIN
DECLARE splitfactor FLOAT;
SELECT IFNULL(EXP(SUM(LOG(f.p_split_factor))),1) INTO splitfactor
FROM fp_v2_fp_basic_splits AS f
WHERE f.fsym_id = id AND f.p_split_date > startdate AND f.p_split_date < NOW();
RETURN splitfactor;
END$$
DELIMiTER ;
Second one is:
DELIMITER $$
DROP FUNCTION IF EXISTS fp_splitadjprice;
CREATE FUNCTION 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_splitfactor(id, startdate) INTO splitfactor;
SELECT (p_price * splitfactor) INTO splitadjprice
FROM fp_v2_fp_basic_prices
WHERE fsym_id = id AND p_date = startdate;
RETURN splitadjprice;
END$$
DELIMITER ;
I then try to exectute a query as the following:
SELECT
p.fsym_id,
b.p_co_sec_name_desc AS Company_Name,
b.region AS Region,
p.p_date,
p.p_price AS Unadjusted_Price,
fp_splitadjprice(p.fsym_id,p_date) AS Adjusted_Price
FROM
fp_v2_fp_basic_prices p
LEFT JOIN (
SELECT r2.region, b2.p_co_sec_name_desc, b2.fsym_id
FROM fp_v2_fp_sec_coverage b2
LEFT JOIN sym_v1_sym_region r2 ON b2.fsym_id = r2.fsym_id
WHERE r2.region = "EUR") b
ON b.fsym_id =p.fsym_id
So basically my query calls the second function, which then calls the first function in order to return a value to the query. The execution is extremely slow though, but I do not understand why that is the case?
I found out that the slow execution was entire due to MySQL workbench not handling large datasets well. Once I migrated everything to BigQuery on Google Cloud everything worked perfectly.
STAY AWAY FROM CALLING FUNCTIONS ON LARGE DATASETS IN MySQL Workbench!

Stored Procedure WHERE OR HAVING Does Not Work

In the below procedure,
It gives error ([Err] 1111 - Invalid use of group function) when I use WHERE statements and it gives another error ([Err] 1054 - Unknown column 'roomid' in 'having clause') when I use HAVING statements instead of WHERE, although I have the roomid column defined in the table.
Does anybody have an idea on how can I fix this issue? The code was working perfectly when I tried under another mySQL version I guess.
DELIMITER //
DROP PROCEDURE IF EXISTS `findAVG`//
CREATE DEFINER=`kamer`#`%` PROCEDURE `findAVG`(IN rid INT, startDate DATETIME, OUT Score DOUBLE)
BEGIN
DECLARE finishDate DATETIME;
DECLARE DateIterator DATETIME;
DECLARE avgPrice DOUBLE;
SET avgPrice = 0;
SET Score = 0;
SELECT price into Score
FROM bookings
WHERE roomid = rid
ORDER BY ABS( DATEDIFF( bookings.date, startDate)) LIMIT 1;
IF (Score = 0) THEN
SET DateIterator = startDate;
SET finishDATE = DATE_ADD(startDate, INTERVAL 30 DAY);
WHILE DateIterator <= finishDate DO
SELECT price
INTO avgPrice
FROM prices
WHERE roomid = rid
AND date = DateIterator
ORDER BY DATEDIFF(startDate, prices.timestamp) LIMIT 1;
SET DateIterator = DATE_ADD(DateIterator, INTERVAL 1 DAY);
END WHILE;
SET Score = AVG(avgPrice);
END IF;
UPDATE bookings SET price=Score WHERE roomid= rid AND date=startDate;
END
"Invalid use of group function" mean you've used a column in the group by function that does not appear in the select clause or the inverse.
i.e. :
SELECT A,B,C,COUNT(*) FROM mytable GROUP BY A,B,C
Grouping is done on the 3 firts's columns and the count is done on each line where A,B and C are similar.
For example, if you try to pass "GROUP BY A,B" SQL wont know what to do with C column...
For HAVING problem, it seem to me the HAVING clause is applicated after the select have been done.
So if you're using a column that doesn't appear in the SELECT clause, then it raise an error.