User defined function only returns NULL - mysql

I have this following MySQL code:
DELIMITER $$
CREATE FUNCTION durationInMinutes(id INT)
RETURNS INT DETERMINISTIC
BEGIN
DECLARE Minutes INT;
SET Minutes =
(SELECT TIME_TO_SEC(TIMEDIFF(timeDeparture, timeArrival)) FROM AirRoute
WHERE pk_id = id) / 60;
RETURN Minutes;
END$$
DELIMITER;
Basically, this function calculates the duration of a flight in minutes. The parameter is the id of the flight. For some reason though, this function always returns NULL. I even checked this:
SELECT (SELECT TIME_TO_SEC(TIMEDIFF(timeDeparture, timeArrival)) FROM AirRoute
WHERE pk_id = 925) / 60;
This does return the correct answer if I put id = 925, so there could be something wrong with the RETURN statement.

I suspect there is a column called id in the table. I always name parameters and local variables in a way to distinguish them from column names:
CREATE FUNCTION durationInMinutes (
in_id INT
)
RETURNS INT DETERMINISTIC
BEGIN
DECLARE out_Minutes INT;
SELECT out_Minutes := TIME_TO_SEC(TIMEDIFF(timeDeparture, timeArrival))
FROM AirRoute ar
WHERE ar.pk_id = in_id) / 60;
RETURN out_Minutes;
END$$

Ok, I solved it. This is my corrected code:
DELIMITER $$
CREATE FUNCTION durationInMinutes(id INT)
RETURNS INT DETERMINISTIC
BEGIN
RETURN (SELECT TIME_TO_SEC(TIMEDIFF(timeDeparture, timeArrival))
FROM AirRoute
WHERE pk_id = id / 60);
END$$
DELIMITER ;
Still, I really don't understand why it wasn't possible using a temp variable.

Related

MySQL: Function not returning the correct integer

We have a question regarding a function returning the wrong integer-value in MySQL. We have checked that "booked_passengers" contains the right value, 0, and it works just fine when removing that variable, meaning just returning the integer 40. But as soon as we try to subtract "booked_passengers" from it, which still should end up returning 40, it does not work.
Including the code below.
Thanks in advance! :-)
CREATE FUNCTION calculateFreeSeats(flightnumber INT)
RETURNS INT
NOT DETERMINISTIC
BEGIN
DECLARE booked_passengers INT;
SELECT BOOKED_PASSENGERS INTO booked_passengers FROM FLIGHT WHERE (flightnumber = NR);
RETURN (40-booked_passengers);
END $$
When column name and local variable name interfere and there is no table alias then the variable is preferred. So your SELECT BOOKED_PASSENGERS ... selects variable value, not column value. Use
CREATE FUNCTION calculateFreeSeats(flightnumber INT)
RETURNS INT
READS SQL DATA
BEGIN
DECLARE booked_passengers INT;
SELECT FLIGHT.BOOKED_PASSENGERS INTO booked_passengers FROM FLIGHT WHERE (flightnumber = NR);
RETURN (40-booked_passengers);
END $$
From the other side the variable usage is obviously excess:
CREATE FUNCTION calculateFreeSeats(flightnumber INT)
RETURNS INT
READS SQL DATA
RETURN (SELECT 40 - BOOKED_PASSENGERS FROM FLIGHT WHERE flightnumber = NR LIMIT 1);

How to create a function that return the number of rows of a table?

Hey guys i have a homework about doing a function in MySQL.
This is the solution in SQL SERVER, but how do i do it in MySQL?
CREATE FUNCTION NumberOfRows()
RETURNS INT
BEGIN
DECLARE #numberOfRows int
set #numberOfRows = (Select COUNT(id) From Producto)
return #numberOfRows
END
print dbo.NumberOfRows()
CREATE FUNCTION NumberOfRows()
RETURNS integer
deterministic
BEGIN
RETURN (SELECT count(idpais)
FROM pais);
END;

Slow nested function

Please let me know what information you seek to improve the question, rather than just downvoting.
I have a function that looks like this:
DELIMITER $$
DROP FUNCTION IF EXISTS f_splitadjprice;
CREATE FUNCTION f_splitadjprice (id CHAR(8), startdate DATE)
RETURNS FLOAT
BEGIN
DECLARE splitfactor FLOAT;
DECLARE splitadjprice FLOAT;
SELECT f_splitfactor(id, startdate) INTO splitfactor;
SELECT (f.p_price FROM fp_v2_fp_basic_prices as f WHERE f.fsym_id = id AND
f.p_date = startdate) * splitfactor INTO splitadjprice;
RETURN splitadjprice;
END$$
DELIMITER ;
The function for splitfactor is:
DELIMITER $$
DROP FUNCTION IF EXISTS f_splitfactor;
CREATE FUNCTION f_splitfactor (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 ;
The function f_splitadjprice runs extremely slow. About 14 seconds PR row. I have tried to run the individual pieces of the function by themselves. That is, the function call f_splitfactor and SELECT (f.p_price FROM fp_v2_fp_basic_prices as f WHERE f.fsym_id = id AND
f.p_date = startdate). When running these two by themselves outside of the function they take 0,001 seconds to run. So the whole problem is that as soon as I want to do in combination through the nested function it takes 100.000 times longer?
The solution is to not call tables within functions. In general that seems to be bad practice and it is nevertheless extremely slow. One should instead try to get rid of the function and perform the function directly in the query.

Pass the columns of each row in a result set to a stored function in single step

The following is my stored function
DELIMITER $$;
CREATE FUNCTION set_credit_values (emp_id bigint, lpc_id int, elc_date date) RETURNS date DETERMINISTIC
BEGIN
SELECT do_credit(emp_id, lpc_id, elc_date,ltp_id, lpb_cr_count, lpb_cr_on, lpb_next_cr, lpb_cr_period)
FROM erp_leave_policy_body,erp_leave_type
WHERE lpb_fk_leave_policy = lpc_id AND ltp_id = lpb_fk_leave_type AND ltp_status=1;
RETURN elc_date;
END $$;
DELIMITER ;
I need to pass the selected values in each row in the result set (by the SELECT query) to do_credit() function. But it is showing errors as
#1415 - Not allowed to return a result set from a function
The do_credit() function is as
DELIMITER $$;
CREATE FUNCTION do_credit (emp_id bigint, lpc_id int, new_elc_date date,ltp_id int, cr_count tinyint, cr_on tinyint, next_cr date, cr_period tinyint)
RETURNS boolean DETERMINISTIC
BEGIN
DECLARE next_credit_date DATE DEFAULT NULL;
DECLARE is_credited INT(11) DEFAULT 0;
SET next_credit_date = get_next_credit(emp_id, lpc_id, new_elc_date,ltp_id, cr_on, next_cr, cr_period);
IF next_credit_date = new_elc_date THEN
SELECT COUNT(*) INTO is_credited FROM erp_employee_leave_credits WHERE
elc_fk_employees = emp_id AND elc_fk_leave_policy = lpc_id AND elc_fk_leave_type = ltp_id AND elc_date = new_elc_date;
-- If the leave is not credited yet
IF is_credited = 0 THEN
INSERT INTO erp_employee_leave_credits(elc_fk_employees,elc_fk_leave_policy,elc_fk_leave_type,elc_date,elc_cr_count) VALUES (emp_id,lpc_id,ltp_id,new_elc_date,cr_count);
END IF;
END IF;
RETURN 1;
END $$;
DELIMITER ;
It is working successfully.
I know using cursor. But when using cursor I should traverse through each row in the result set. So may take more time. If I call the function with the select query it works faster than cursor. So How can solve this error.

MySQL Function: Selecting and returning column

I have a table Processes, which consists of an ID (unsigned int, auto_increment) and Name (varchar, unique).
Selecting the following function with any input (whether in the table or not) always results in
ERROR 1172 (42000): Result consisted of more than one row
CREATE FUNCTION LookupOrInsertProcess(nametwo VARCHAR(255))
RETURNS INT UNSIGNED
BEGIN
DECLARE myid INT UNSIGNED;
SELECT ID INTO myid FROM Processes WHERE Name=nametwo;
RETURN myid;
END$$
However, selecting the below function always returns NULL:
CREATE FUNCTION LookupOrInsertProcess(nametwo VARCHAR(255))
RETURNS INT UNSIGNED
BEGIN
DECLARE myid INT UNSIGNED;
SELECT ID INTO myid FROM Processes WHERE Name=nametwo;
RETURN myid;
END$$
Furthermore, please note that the following does return the correct result (numbers 30 and 50 are arbitrary):
CREATE FUNCTION LookupOrInsertProcess(nametwo VARCHAR(255))
RETURNS INT UNSIGNED
BEGIN
DECLARE myid INT UNSIGNED;
SELECT ID INTO myid FROM Processes WHERE Name=nametwo;
IF myid IS NULL THEN
RETURN 30;
ELSE
RETURN 50;
END IF;
END$$
Any help is appreciated.
UPDATE: Edited to remove clash between table column and function param. I don't believe that's the issue.
UPDATE2: Please note that the following appears to work, both when the input param is or is not in the table. Why, without the coalesce(), does the function return NULL even for input params which are in the table?
CREATE FUNCTION LookupOrInsertProcess(nametwo VARCHAR(255))
RETURNS INT UNSIGNED
BEGIN
DECLARE myid INT UNSIGNED;
SELECT ID INTO myid FROM Processes WHERE Name=nametwo;
RETURN COALESCE(myid, 0);
END$$
Column names are not case-sensitive in MySql so you may find that where Name = name means 'give me every row'.
Try changing the input parameter to your procedure (and the corresponding condition in the query) to be srchName or something else different to name.
Try to rename input name to different name like inputName.
Update:
Another suggestion.
DECLARE myid INT UNSIGNED;
SET myid = (SELECT ID FROM Processes WHERE Name=nametwo);
RETURN myid;