Mysql calculate the average of a function's parameter - mysql

Here is a function to describe my question:
CREATE DEFINER=`root`#`localhost` FUNCTION `Demo`(`data` Integer) RETURNS int(11)
BEGIN
declare result integer;
set result = avg(`data`);
return result;
RETURN 1;
END
And the parameter data is a whole column from other select result, just looks like:
10
12
15
...
I want to use this function to calculate the average of the data, but it just shows:
Error Code: 1111. Invalid use of group function
It seems that was a wrong way to use the avg function, and other function like count() has the same problem too, but I can't find a way to achieve my purpose, is there a way to do that?

It makes no sense to calculate the average of a single value. The average of a single value is the same as the min and the same as the max, and these are all equal to the single value itself.
It's hard to tell what you intend this function to do. If you want to use it in a query, you can calculate the average of its result as you use it on each row of a query:
SELECT AVG(Demo(data)) FROM MyTable;
Or you can use the function to query some table and return the average of many rows. But then you don't need to pass any function argument.
CREATE FUNCTION Demo() RETURNS INT
BEGIN
DECLARE result INT;
SET result = (SELECT AVG(`data`) FROM MyTable);
RETURN result;
END

You would have to pass it an array.
CREATE DEFINER=`root`#`localhost` FUNCTION `Demo`(a_array IN my_integer_array) RETURNS int(11)
BEGIN
FOR i IN a_array.first..a_array.last LOOP
set result = a_array(i);
return result;
END LOOP;
RETURN 1;
END

Related

Why does my SQL function return a table when I want it to return a single value?

I want to write a function because I need the laststop value in a subsequent question calculation the bus fare with a pair of bus stops. If the alight bus stop value is Null the last stop will be used to calculate the fair.
for example, test data for bus service 77:
stoprank table
I want the function to return stopid "40129" for sid = 77 so I can do this:
select fare
from busfare
where boardtstop = 'xxx' and
alightstop = if(boardstop is not null,boardstop,laststop(77))
I also need the stop value for other questions as well when alightstop is null.
I hope I'm clear enough, the actual question is more complicated I'm trying to simplify it.
I have a table called stoprank which has columns: stopid, sid(bus service id), stoprank. I want to create a function laststop that takes in a bus service id and returns the last stop of the service(highest stoprank).
Overview of the stoprank table
I wrote the following function:
delimiter $$
create function LastStop (serviceID int)
returns int
DETERMINISTIC
begin
declare laststopid int;
set laststopid = (select stopid from stoprank where sid = serviceID and
rankorder = (select max(rankorder) from stoprank where sid = serviceID));
return laststopid;
end $$
delimiter ;
However, instead of returning one value, the last stop, it returns a table of the same value:
actual output
expected output
The value is correct but the format is wrong, I can't figure out why.
You should write the code in this way.
(select stopid from stoprank where sid = serviceID order by rankorder desc limit 1);

How can I fix a MySQL Error, Not allowed to return a result set from a function

CREATE FUNCTION `ConvertDate`(StringDate varchar(15))
RETURNS datetime
BEGIN
declare CDATE varchar(10);
SET CDATE = StringDate;
select str_to_date(CDATE,'%Y%m%d %h%i');
RETURN CDATE;
END
I get an error:
Error Code: 1415 Not allowed to return a result set from a function
How can I fix this Error?
Your problem is that your SELECT statement has no INTO clause, so it attempts to return the result set from the function. You could alter that to:
SELECT STR_TO_DATE(CDATE,'%Y%m%d %h%i') INTO CDATE;
But you might as well do all the computation in the RETURN statement:
CREATE FUNCTION `ConvertDate2`(StringDate varchar(15))
RETURNS datetime
RETURN STR_TO_DATE(StringDate,'%Y%m%d %h%i');
You should
Select INTO cdate...
or don't bother with the select and
set cdate = str_to_date..
BUT Unless this is a very simplified version of your actual function I don's see the point of the function.

GROUP_CONCAT as input of MySQL function

Is it possible to use a GROUP_CONCAT in a SELECT as the input of a MySQL function? I cannot figure out how to cast the variable it seems. I've tried blob. I've tried text (then using another function to break it up into a result set, here) but I haven't had any success.
I want to use it like this:
SELECT
newCustomerCount(GROUP_CONCAT(DISTINCT items.invoicenumber)) AS new_customers
FROM items;
Here is the function:
DROP FUNCTION IF EXISTS newCustomerCount;
DELIMITER $$
CREATE FUNCTION newCustomerCount(invoicenumbers BLOB)
RETURNS INT
DETERMINISTIC
BEGIN
DECLARE new_customers INT;
SET new_customers = 0;
SELECT
SUM(nc.record) INTO new_customers
FROM (
SELECT
1 AS customer,
(SELECT COUNT(*) FROM person_to_invoice ps2 WHERE person_id = ps1.person_id AND invoice < ps1.invoice) AS previous_invoices
FROM person_to_invoice ps1
WHERE invoice IN(invoicenumbers)
HAVING previous_invoices = 0
) nc;
RETURN new_customers;
END$$
DELIMITER ;
Because Mysql functions do not support dynamic queries, I recommend you re-think your basic strategy to pass in a list of invoice numbers to your function. Instead, you could modify your function to accept a single invoice number and return the number of new customers just for the one invoice number.
Also, there are some optimizations you can make in your query for finding the number of new customers.
DROP FUNCTION IF EXISTS newCustomerCount;
DELIMITER $$
CREATE FUNCTION newCustomerCount(p_invoice INT)
RETURNS INT
DETERMINISTIC
BEGIN
DECLARE new_customers INT;
SET new_customers = 0;
SELECT
COUNT(DISTINCT ps1.person_id) INTO new_customers
FROM
person_to_invoice ps1
WHERE
ps1.invoice = p_invoice
AND NOT EXISTS (
SELECT 1
FROM person_to_invoice ps2
WHERE ps1.person_id = ps2.person_id
AND ps2.invoice < ps1.invoice
);
RETURN new_customers;
END$$
DELIMITER ;
Then you can still get the total number of new customers for a given list of invoice numbers like this:
SELECT
SUM(newCustomerCount(invoice)) as total_new_customers
FROM items
WHERE ...
You could try FIND_IN_SET() instead of IN(). The performance will probably be horrible when passing in a long list of invoice numbers. But it should work.
WHERE FIND_IN_SET(invoice, invoicenumbers)
You are looking in the wrong place.
WHERE invoice IN(invoicenumbers) will not do the desired substitution. Instead you need to use CONCAT to construct the SQL, then prepare and execute it.

Table Parameter in MySQL Function

Basically I am trying to refer to my table in mysql function, so that in my query I can say "from x" as in x is a parameter of the function, so that someone can put in the table they want the function to run on.
CREATE DEFINER=`root`#`localhost` FUNCTION `somefunction`(t varchar(8), num integer) RETURNS int(8)
BEGIN
DECLARE result integer(12);
DECLARE test varchar(12);
SET result = 0;
SET test = t;
select integer * 5 INTO result from x;
return result;
END
Basically when I do somefunction(thisisthetableiwant, 5) I get an error saying that it cannot find 'test in field list' so it isn't setting the table to what I put in the parameter, currently I have the part "from x" hardcoded with the table I want and it works but I need to make it so I can have a parameter incase I need to use the function on another table

Return value from Function in MySQL

Hi I try to write a function in MySQL, which gives me back a value from a table.
I'm getting the error:
Error Code: 1415. Not allowed to return a result set from a function
I know what it means, but I don't know how to solve the problem. I just need one value, the Id of the inserted row. I'm glad for any help.
What the function does is:
Insert a new row into the aip_request table, with a Random value, that way I can identify the row after the insert. The function should return the Id of the created line.
The request_id is an autovalue.
DROP FUNCTION IF EXISTS `sp_get_new_request_id`;
DELIMITER $$
CREATE FUNCTION `sp_get_new_request_id` ()
RETURNS BIGINT
BEGIN
DECLARE var_random bigint;
SET #random := CAST(RAND(NOW()) AS CHAR(150));
INSERT INTO aip_request
(Firstname)
VALUES( #random );
SELECT request_id INTO var_random FROM aip_request
WHERE Firstname = #random
LIMIT 1;
Return var_random;
END
$$
Change this query -
SELECT #random := CAST(RAND(NOW()) AS CHAR(150));
with this one -
SET #random := CAST(RAND(NOW()) AS CHAR(150));
...you cannot execute SELECT query that returns data-set from the stored function.