MYSQL function parameter not working on internal select - mysql

I'm creating a function that has a SELECT inside another SELECT.
When i try to use one of the function parameters as part of the internal SELECT it returns nothing.
FUNCTION `nota_alumno`(`uid` VARCHAR(255), `total_p` INT) RETURNS float
BEGIN
RETURN (SELECT (SUM(n_pregunta)*10)/total_p AS nota
FROM
(SELECT nota_pregunta(scores.userid,question) as n_pregunta FROM `scores` WHERE scores.userid=uid GROUP BY question) as T);
END
It does work when i just put a non parameter-based value:
FUNCTION `nota_alumno`(`uid` VARCHAR(255), `total_p` INT) RETURNS float
BEGIN
RETURN (SELECT (SUM(n_pregunta)*10)/total_p AS nota
FROM
(SELECT nota_pregunta(scores.userid,question) as n_pregunta FROM `scores` WHERE scores.userid="ddj239dkdsd" GROUP BY question) as T);
END
For reference as requested, here is the definition of the function nota_pregunta:
FUNCTION `nota_pregunta`(`userid` VARCHAR(255), `q` INT) RETURNS float
BEGIN
RETURN (SELECT ROUND(1/COUNT(*),2) FROM `scores` WHERE userid=userid and question=q);
END

The subquery is excess. BEGIN_END is excess too.
FUNCTION nota_alumno(uid VARCHAR(255), total_p INT)
RETURNS float
RETURN ( SELECT SUM(nota_pregunta(userid, question)) * 10 / total_p AS nota
FROM scores
WHERE scores.userid=uid
GROUP BY question
);
Also the finction nota_pregunta is not correct (in WHERE userid=userid you compare parameter and parameter, i.e. you check that provided userid is not NULL), must be
FUNCTION nota_pregunta(userid VARCHAR(255), q INT)
RETURNS float
RETURN ( SELECT ROUND(1/COUNT(*),2)
FROM scores
WHERE scores.userid=userid AND question=q);

Related

I have a scalar function that returns a varchar(100) containing this "(289/2.2)*.8". How can I make the function return 105.090909090909091 instead?

In the table Health Functions I have a row for ProteinUSRDA which has the function ({weight}/2.2)*.8 . I created a scalar function that accepts the profileid (to get the weight) and a NutritionFunctionID and it will return (289/2.2)*.8 for the selected user as a varchar(100) It would be awesome if I could get the function to return the results calculated out. Is there a way?
CREATE FUNCTION [dbo].[MyProteinRDA]
(
-- Add the parameters for the function here
#ProfileID int,
#FID int
)
RETURNS varchar(100)
AS
BEGIN
return (Select Replace(FFunction,'{Weight}',(Select weight from profile where profileid = #ProfileID)) from HealthFunctions where FID = 4);
END
if I use exec the rendered function it works but I can not find a way to return it from the SQL function.

Select inside function not working as expected

I have created a function to encapsulate a select on PL/SQL.
But the result I get from using the function is different that the one I get from using the select on it's own.
CREATE OR REPLACE FUNCTION fecha_ultimo_trasiego(fermentacion IN VARCHAR2)
RETURN DATE
IS fecha DATE;
BEGIN
SELECT (
SELECT fecha
FROM (
SELECT t.id, t.fecha
FROM TrasiegoAux t
WHERE t.fermentacion=fermentacion
ORDER BY t.fecha desc
)
WHERE ROWNUM=1
) INTO fecha FROM DUAL;
RETURN(fecha);
END;
Is there something wrong on the declaration of my function? Right now it always returns the same value no matter what parameter it gets as input.
The expected output is the date of the last Trasiego (the max date of the table).
This is my structure:
CREATE TABLE Fermentacion(
id VARCHAR2(36)
);
CREATE TABLE Trasiego(
id VARCHAR2(36),
fecha DATE not null,
fermentacion VARCHAR2(36) REFERENCES Fermentacion,
temperatura NUMBER(8) not null,
litrosFinal NUMBER(8) not null,
PRIMARY KEY(id, fermentacion)
);
create or replace view TrasiegoAux as select id, fecha, fermentacion from Trasiego;
Here is some data:
Insert into FERMENTACION (ID) values ('4');
Insert into FERMENTACION (ID) values ('9');
Insert into TRASIEGO (ID,FERMENTACION,TEMPERATURA,LITROSFINAL,FECHA) values ('1','4',20,190,to_date('04-OCT-16','DD-MON-RR'));
Insert into TRASIEGO (ID,FERMENTACION,TEMPERATURA,LITROSFINAL,EMPLEADOLABORATORIO,FECHA) values ('2','4',20,180,to_date('11-OCT-16','DD-MON-RR'));
Insert into TRASIEGO (ID,FERMENTACION,TEMPERATURA,LITROSFINAL,FECHA) values ('3','9',20,190,to_date('04-OCT-16','DD-MON-RR'));
Given that data I would expect that this:
DECLARE
fecha date;
BEGIN
fecha :=fecha_ultimo_trasiego(4);
DBMS_OUTPUT.PUT_LINE(fecha); //'11-OCT-16'
fecha :=fecha_ultimo_trasiego(4);
DBMS_OUTPUT.PUT_LINE(fecha); //'04-OCT-16'
END;
It's most likely to be because you're passing in the parameter with the same name as the column. That's not a good idea, as it causes all sorts of strangeness.
You can either amend the parameter name, e.g.:
CREATE OR REPLACE FUNCTION fecha_ultimo_trasiego(p_fermentacion IN VARCHAR2)
...
WHERE t.fermentacion = p_fermentacion
...
or you could qualify the parameter name in the query:
CREATE OR REPLACE FUNCTION fecha_ultimo_trasiego(fermentacion IN VARCHAR2)
...
WHERE t.fermentacion = fecha_ultimo_trasiego.fermentacion
...
You need to give the parameter a different name to any of the columns in TrasiegoAux, or else prefix it with the function name, e.g.
WHERE t.fermentacion = fecha_ultimo_trasiego.fermentacion
or else (after renaming the parameter):
WHERE t.fermentacion = p_fermentacion
Edit: Boneist beat me to it.
You could probably simplify the code a bit, though, as the select ... from dual wrapper doesn't seem to be needed:
create or replace function fecha_ultimo_trasiego
( p_fermentacion in trasiegoaux.fermentacion%type )
return date
as
l_fecha date;
begin
select fecha into l_fecha
from ( select t.fecha
from trasiegoaux t
where t.fermentacion = p_fermentacion
order by t.fecha desc )
where rownum = 1;
return l_fecha;
end;

MySql Function Creation Error

I write a function like the following. the purpose of this function is to return the place of a student by some specific exam in a branch.
DELIMITER $$
CREATE FUNCTION `getMerit`( branch VARCHAR(50), totalMark DECIMAL(19,2), comaSeparetedExamIds VARCHAR(200) ) RETURNS INT(11)
BEGIN
SET #comaSeparetedExamIds=comaSeparetedExamIds;
SET #branch =branch;
SET #marks=totalMark;
SELECT #place=COUNT(*)+1
FROM (
SELECT SUM(m.marks) marks
FROM marksheet m, studentinfo s
WHERE exam_id IN (#comaSeparetedExamIds)
AND m.student_roll=s.roll_no
AND s.branch LIKE CONCAT(#branch,'%')
GROUP BY m.student_roll
) AS a
WHERE a.marks>#totalMark;
RETURN #place;
END$$
DELIMITER ;
But It shows me an error. the Error is
Query : CREATE FUNCTION getMerit( branch varchar(50), totalMark
DECIMAL(19,2), comaSeparetedExamIds varchar(200) ) RETURNS int(11)
BEG... Error Code : 1415 Not allowed to return a result set from a
function
What mistake I made here, Can anyone please help me?
You can't name input variables with #. # is used for user variables, ie connection local variables that don't needs to be declared.
Also you can't have selects in functions.
Procedures can return result sets but return values.
Functions can return values but not result sets.
They also differs in how you use them.
select function_name(1) from dual;
select id, name, funcation_name(id, name) from anyTable;
call procedure_name(1);
And when assigning variables inside selects you need to do := and not =. In your code you are actually selecting true or false and not the count.
This should work.
DELIMITER $$
CREATE FUNCTION `getMerit`( branch VARCHAR(50), totalMark DECIMAL(19,2), comaSeparetedExamIds VARCHAR(200) ) RETURNS INT(11)
BEGIN
SET #comaSeparetedExamIds=comaSeparetedExamIds;
SET #branch =branch;
SET #marks=totalMark;
SELECT COUNT(*)+1 INTO #place
FROM (
SELECT SUM(m.marks) marks
FROM marksheet m, studentinfo s
WHERE exam_id IN (#comaSeparetedExamIds)
AND m.student_roll=s.roll_no
AND s.branch LIKE CONCAT(#branch,'%')
GROUP BY m.student_roll
) AS a
WHERE a.marks>#totalMark;
RETURN #place;
END$$
DELIMITER ;

How to declare table in SQL Server?

I am trying to create a function which needs to return a table but even function is not made too and I need to return the resulted table.
My script is like this
create function FNC_getPackageListById(#PkId int )
returns table
as
return
if exists (select Date1, Date2 from PromotionPackage
where PkId = #PkId and Date1 is null and Date2 is null)
begin
select Rate,Remarks,PackageName from Package where PkId=#PkId
end
else
begin
select p.Rate,
p.Remarks,
p.PackageName,
pp.Date1,
pp.Date2
from PromotionPackage pp,
Package p
where pp.PkId=p.PkId and p.PkId=#PkId
end
end
The function called table valued function that returns a table. See this example:
CREATE FUNCTION TrackingItemsModified(#minId int)
RETURNS #trackingItems TABLE (
Id int NOT NULL,
Issued date NOT NULL,
Category int NOT NULL,
Modified datetime NULL
)
AS
BEGIN
INSERT INTO #trackingItems (Id, Issued, Category)
SELECT ti.Id, ti.Issued, ti.Category
FROM TrackingItem ti
WHERE ti.Id >= #minId;
RETURN;
END;

PostgreSQL: Call a Function More Than Once in FROM Clause

How can I call a function which returns records more than once in FROM clause? I understand that I have to specify a 'column definition list' when using a function that returns records. But how can I then use aliases for that function?
Example:
CREATE OR REPLACE FUNCTION foo(which_foo int) RETURNS SETOF RECORD AS
$BODY$BEGIN
IF which_foo=0 THEN
RETURN QUERY EXECUTE 'SELECT 1::int,2::int;';
ELSE
RETURN QUERY EXECUTE 'SELECT 1::int,2::int;';
END IF;
END$BODY$
LANGUAGE plpgsql;
SELECT * FROM foo(0) AS (a int, b int);;
SELECT * FROM foo(1) AS (c int, d int);
SELECT * FROM foo(0) AS (a int, b int), foo(1) AS (c int, d int);
The last select statement will fail with:
ERROR: table name "foo" specified more than once
I want to keep using the column definition list, because the function I want to use in the end has to be as generic as possible.
SELECT f0.*, f1.*
FROM
foo(0) AS f0 (a int, b int),
foo(1) AS f1 (c int, d int);
I understand that I have to specify a 'column definition list' when
using a function that returns records.
No, you do not. I wouldn't operate with anonymous records. Declare the return type, since you already know it:
CREATE OR REPLACE FUNCTION foo(which_foo int)
RETURNS TABLE (a int, b int) AS
$func$
BEGIN
IF which_foo = 0 THEN
RETURN QUERY SELECT 1,2;
ELSE
RETURN QUERY SELECT 1,2;
END IF;
END
$func$ LANGUAGE plpgsql;
And assuming you do not want to combine multiple calls into one row, you should use UNION ALL:
SELECT * FROM foo(0)
UNION ALL
SELECT * FROM foo(1);