Select inside function not working as expected - function

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;

Related

How to pass multiple parameters into a mysql stored procedure

I have a stored procedure that I am working on that is returning an invalid return when I try to pass parameters to it compared to when I run it with hard-coded values.
Procedure with hard coded values:
BEGIN
SELECT COUNT(DISTINCT ItemID)
FROM (
SELECT *
FROM sandbox_inventoryitempurchase
WHERE OrgID = '2781823'
AND PurchaseMonth>'2015-03-01'
) as DistinctCount;
END
When run, this returns: 16 which is correct.
Procedure with two input parameters:
BEGIN
SELECT COUNT(DISTINCT ItemID)
FROM (
SELECT *
FROM sandbox_inventoryitempurchase
WHERE OrgID = orgid
AND PurchaseMonth>sincedate
) as DistinctCount;
END
The input parameters are defined as:
IN userid integer,IN orgid integer,IN sincedate date
When run, this returns: 334 which is not correct.
I am new to stored procedures and would appreciate any assistance offered regarding what I am doing wrong and what I need to do to resolve?
Thanks...
add "#" before your parameters:
BEGIN
SELECT COUNT(DISTINCT ItemID)
FROM (
SELECT *
FROM sandbox_inventoryitempurchase
WHERE OrgID = #orgid
AND PurchaseMonth>#sincedate
) as DistinctCount;
END
a fast turtorial will be: Write-a-Stored-Procedure-in-SQL
(see how to use parameters at the end of this page...)
Try using input parameters that are not the same name as your columns.
Change:
BEGIN
SELECT COUNT(DISTINCT ItemID)
FROM (
SELECT *
FROM sandbox_inventoryitempurchase
WHERE OrgID = orgid
AND PurchaseMonth>sincedate
) as DistinctCount;
END
To:
BEGIN
SELECT COUNT(DISTINCT ItemID)
FROM (
SELECT *
FROM sandbox_inventoryitempurchase
WHERE OrgID = p_orgid
AND PurchaseMonth > p_sincedate
) as DistinctCount;
END
And pass IN p_orgid integer,IN p_sincedate date
The parser may be seeing WHERE OrgID = orgid and that evaluates to true for every record since it evaluates as an identity (comparing against itself).
Param Name and field name must be different!
BEGIN
SELECT COUNT(DISTINCT ItemID)
FROM (
SELECT *
FROM sandbox_inventoryitempurchase
WHERE OrgID = p_orgid
AND PurchaseMonth > p_sincedate
) as DistinctCount;
END

How to add the additional column that contains the list of values?

1) I have a query that writes the list of actions to temp table1:
declare #table1 table (ActionName varchar(250), ActionDate datetime, ... Description varchar(100))
insert into #table1(ActionName, ActionDate, ... Description)
select --Search actions by ActionName
The actions can have multiple action dates, which is important and it means we can have multiple records with the same action name, but different action dates.
2) I have to reduce table1 to get all action names appears only once, but with additional field DateList (comma separated string) that should contain the list of all date actions (ActionDate field) for that action:
declare #table2 table (ActionName varchar(250), ActionDate datetime, ... Description varchar(100), DateList varchar(4000))
I know how to create the list of action dates:
declare #dateList varchar(4000)
select #dateList = coalesce(#dateList + ', ', '') + convert(varchar, ActionDate, 120)
from #temp
But, I'm not sure how to incorporate it in the whole solution.
You need to wrap your list-creation code in a function and then use that on your table like this:
insert into #table2
select ActionName, uf_GetDateList(ActionName)
from #table1
group by ActionName
Now the function itself is a tricky part. You need to pass the #table1 down there somehow. You can either turn #table1 into a temporary table #table1 then you would do something like this:
select #dateList = coalesce(#dateList + ', ', '') + convert(varchar, ActionDate, 120)
from #temp1
where ActionName=#ActionName
Or you can use table-valued parameter to pass the table variable into the function.

MySql Stored Proc - Select query returns null if using where clause not included in select list?

I have a proc that simply contains the following:
SELECT Col1, Col2 FROM table WHERE Id = 1;
This always returns null values. If I change the statement to:
SELECT Id, Col1, Cold2 FROM table WHERE Id = 1;
The row gets returned as expected. Does mySql procs demand that the where clause columns appear in the select list? It doesn't have this behaviour when running the SQL directly in phpMyAdmin.
Here's the code in question:
CREATE PROCEDURE sp_player_login
(
IN
userGraphId INT(11),
authToken TEXT
)
BEGIN
DECLARE playerId INT;
DECLARE newPlayer BOOLEAN DEFAULT FALSE;
SELECT Id INTO playerId FROM player WHERE FacebookGraphId = userGraphId;
If playerId IS NULL THEN
-- Create the player.
SET newPlayer = TRUE;
-- Get new player defaults.
SELECT NewPlayerTurns, NewPlayerMoney, NewPlayerMorale, NewPlayerMissilePower FROM defaults WHERE Id = 1;
END IF;
END #
The second SELECT NewPlayerTurns... is the one that returns null values if I don't specify the Id column in the select clause. If I remove the first SELECT Id INTO ...the second query works without the Id in the select clause...? confused

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;