While loop in IBM DB2 stored procedure endup in infinite looping - stored-procedures

I am new with procedure. Somewhat I am getting the results too. But I got problem with a dynamic query. Stored query in a variable and tried to execute using cursor. But the loop only select the first result and execute infinitely. I couldn't find the error. How can I clear the error? Any help would be appreciated.
My Procedure is
CREATE PROCEDURE SPTEST1(IN tr_code INT, IN pen_type INT, IN pen_code INT, IN due_code INT, IN ord_dt DATE, IN finyr_cd INT, IN user_id varchar(50), IN server_ip varchar(100), OUT res INTEGER)
SPECIFIC sptest1
LANGUAGE SQL
P1:BEGIN
DECLARE trcd INTEGER;
DECLARE pentyp INTEGER;
DECLARE pencd INTEGER;
DECLARE duecd INTEGER;
DECLARE orddt DATE;
DECLARE finyrcd INTEGER;
DECLARE userid VARCHAR(50);
DECLARE serverip VARCHAR(100);
DECLARE ls_pentype CHAR(1);
DECLARE ls_voted CHAR(1);
DECLARE li_crmonth INTEGER;
DECLARE li_cryear INTEGER;
DECLARE ls_adhoc CHAR(1);
DECLARE ld_elgdt DATE;
DECLARE li_duecode INTEGER;
DECLARE li_headid INTEGER;
DECLARE tr_whr varchar(500);
DECLARE code_whr varchar(500);
DECLARE sqlstmt varchar(1000);
DECLARE EOF int DEFAULT 0;
DECLARE v_duplicate INT DEFAULT 0;--
DECLARE c_duplicate CONDITION FOR SQLSTATE '23505';
DECLARE STMT VARCHAR(120);
DECLARE SQLCODE INTEGER DEFAULT 0;
DECLARE SQLSTATE CHAR(5) DEFAULT '00000';
SET trcd = tr_code;
SET pentyp = pen_type;
SET pencd = pen_code;
SET duecd = due_code;
SET orddt = ord_dt;
SET finyrcd = finyr_cd;
SET userid = user_id;
SET serverip = server_ip;
SET ls_voted = 'V';
IF duecd > 50 THEN
SET ls_voted = 'C';
END IF;
FOR v_row AS <select query>
DO
SET ls_pentype = v_row.fmly_serv_oth_pen;
END FOR;
FOR date_month AS <select query>
DO
SET li_crmonth = date_month.credit_month;
SET li_cryear = date_month.credit_year;
END FOR;
FOR adhoc_row AS <select query>
DO
SET ls_adhoc = adhoc_row.is_adhoc_due;
END FOR;
FOR elgdt_row AS <select query>
DO
SET ld_elgdt = elgdt_row.eligible_uptodt;
END FOR;
FOR head_row AS <select query>
DO
SET li_headid = head_row.head_id;
SET li_duecode = duecd;
END FOR;
--portion for delete. have to enter
P2:BEGIN
DECLARE TRPOC CURSOR FOR <select query>
OPEN TRPOC;
FETCH FROM TRPOC INTO trcd;
WHILE(SQLSTATE = '00000') DO
insert into bg_run_test values(char(trcd));
END WHILE;
CLOSE TRPOC;
END P2;
END P1#
Here the while loop at the last executing infinitely. Where I try to insert in a table. Actually the result have only 200 rows.But inserting lacks.

I think you need an additional FETCH at the end of the WHILE loop after the INSERT statement, for it to successfully break out.
See this link which explains exactly this scenario.

Related

Error -206 creating Interbase stored procedure

I am attempting to create a stored procedure using an IBConsole interactive SQL window. The intent of the procedure is to gather data from two tables, do some processing on that data, insert rows containing that data into a working table, then return the rows from the working table as the stored procedure result. The stored procedure:
SET TERM ^;
CREATE PROCEDURE BIBLIO_SUBJECT
RETURNS (ID INTEGER, SUBJECT VARCHAR(200))
AS
DECLARE VARIABLE CUR_SUBJECT VARCHAR(200);
DECLARE VARIABLE SUBJECT_LIST VARCHAR(500);
DECLARE VARIABLE BIBLIOID INTEGER;
DECLARE VARIABLE NEXTPOS INTEGER;
BEGIN
DELETE FROM TSUBJECTS;
FOR SELECT BIBLIO.ID, BIBLIO.SUBJECTS
FROM BIBLIO
WHERE BIBLIO.PUBLISH = TRUE
INTO :BIBLIOID, :SUBJECT_LIST
DO
BEGIN
SUBJECT_LIST = BIBLIO.SUBJECTS + ';';
NEXTPOS = LOCATE(";", SUBJECT_LIST);
WHILE (:NEXTPOS > 1) DO
BEGIN
CUR_SUBJECT = SUBSTR(:SUBJECT_LIST, 1, NEXTPOS - 1);
SUBJECT_LIST = SUBSTR(:SUBJECT_LIST, NEXTPOS + 1, STRLEN(SUBJECT_LIST));
INSERT INTO TSUBJECTS (SUBJECT, ID) VALUES(:CUR_SUBJECT, :BIBLIOID);
NEXTPOS = LOCATE(";", SUBJECT_LIST);
END
END
FOR SELECT BIBLIO_BEAST.BIBLIO_ID, BEAST.BEAST_NAME
FROM BIBLIO_BEAST
INNER JOIN BEAST ON (BEAST.ID = BIBLIO_BEAST.BEAST_ID)
INNER JOIN BIBLIO ON (BIBLIO.ID = BIBLIO_BEAST.BIBLIO_ID)
WHERE BIBLIO.PUBLISH = TRUE
INTO :BIBLIOID, :CUR_SUBJECT
DO
BEGIN
INSERT INTO TSUBJECTS (SUBJECT, ID) VALUES(:CUR_SUBJECT, :BIBLIOID);
END
FOR SELECT ID, SUBJECT
FROM TSUBJECTS
INTO :ID, :SUBJECT
DO
SUSPEND;
END^
SET TERM ;^
When I execute the above code in IBConsole I get the error:
Error at line 2
Dynamic SQL Error
SQL error code = -206
Column unknown
SQL - CREATE PROCEDURE BIBLIO_SUBJECT
RETURNS (ID INTEGER, SUBJECT VARCHAR(200))
AS
DECLARE VARIABLE CUR_SUBJECT VARCHAR(200);
DECLARE VARIABLE SUBJECT_LIST VARCHAR(500);
DECLARE VARIABLE BIBLIOID INTEGER;
DECLARE VARIABLE NEXTPOS INTEGER;
BEGIN
DELETE FROM TSUBJECTS;
FOR SELECT BIBLIO.ID, BIBLIO.SUBJECTS
FROM BIBLIO
WHERE BIBLIO.PUBLISH = TRUE
INTO :BIBLIOID, :SUBJECT_LIST
DO
BEGIN
SUBJECT_LIST = BIBLIO.SUBJECTS + ';';
NEXTPOS = LOCATE(";", SUBJECT_LIST);
WHILE (:NEXTPOS > 1) DO
BEGIN
CUR_SUBJECT = SUBSTR(:SUBJECT_LIST, 1, NEXTPOS - 1);
SUBJECT_LIST = SUBSTR(:SUBJECT_LIST, NEXTPOS + 1, STRLEN(SUBJECT_LIST));
INSERT INTO TSUBJECTS (SUBJECT, ID) VALUES(:CUR_SUBJECT, :BIBLIOID);
NEXTPOS = LOCATE(";", SUBJECT_LIST);
END
END
FOR SELECT BIBLIO_BEAST.BIBLIO_ID, BEAST.BEAST_NAME
FROM BIBLIO_BEAST
INNER JOIN BEAST ON (BEAST.ID = BIBLIO_BEAST.BEAST_ID)
INNER JOIN BIBLIO ON (BIBLIO.ID = BIBLIO_BEAST.BIBLIO_ID)
WHERE BIBLIO.PUBLISH = TRUE
INTO :BIBLIOID, :CUR_SUBJECT
DO
BEGIN
INSERT INTO TSUBJECTS (SUBJECT, ID) VALUES(:CUR_SUBJECT, :BIBLIOID);
END
FOR SELECT ID, SUBJECT
FROM TSUBJECTS
INTO :ID, :SUBJECT
DO
SUSPEND;
END
It doesn't say which column is "unknown", and line 2 is (apparently) the RETURNS clause of the CREATE PROCEDURE. Not at all helpful.
Each of the SQL statements in the stored procedure (3 SELECTs, a DELETE, 2 INSERTs) work without error if executed separately in an Interactive SQL window, so all of their columns are "known". BIBLIO_SUBJECT is not the name of an existing stored procedure, nor is it the name of an existing table, or anything else in the database.
This has me baffled. Online searches provide no answer. So I am hoping the clever Stack Overflow people can help me get this working.
David
Well, I figured it out. It was the statement:
SUBJECT_LIST = BIBLIO.SUBJECTS + ';';
The SUBJECT_LIST variable is already used in the preceding select. A silly mistake, but I am old.
Not that it matters since the Interbase UDF functions Locate() and Substr() can only handle 80 character strings, which makes them really useless to me... and probably useless to most.

Can you access the return of a stored proc using cfstoredproc, even if return is not defined as an out parameter?

I have a stored procedure whose return I want to access, using the Coldfusion cfstoredproc tag. However, the return variable is not listed as an out param, along with the 6 "in" params. See procedure's code below:
CREATE PROCEDURE [dbo].[sp_Hire_AddEVerifyEmpCloseCase]
(
#e_verify_id bigint
,#ClientSftwrVer varchar(30)=null
,#CaseNbr char(15)
,#CloseStatus varchar(50)
,#CurrentlyEmployed varchar(1)
,#submit_user_id int
//THIS LINE IS MISSING: #EmpCloseCase_Id int OUTPUT
)
AS
BEGIN
DECLARE #EmpCloseCase_id int
SET #EmpCloseCase_id=0
SELECT #EmpCloseCase_id = EmpCloseCase_id FROM Appl_Hired_EVerify_EmpCloseCase WITH(NOLOCK) WHERE e_verify_id = #e_verify_id
BEGIN TRANSACTION EmpCloseCase
BEGIN TRY
IF(#EmpCloseCase_id = 0) BEGIN
INSERT INTO Appl_Hired_EVerify_EmpCloseCase(e_verify_id,ClientSftwrVer,CaseNbr,CloseStatus,CurrentlyEmployed, systemdate,submit_user_id)
VALUES (#e_verify_id,#ClientSftwrVer,#CaseNbr,#CloseStatus,#CurrentlyEmployed,GETDATE(),#submit_user_id)
SET #EmpCloseCase_id=ISNULL(SCOPE_IDENTITY(),0)
END ELSE BEGIN
UPDATE Appl_Hired_EVerify_EmpCloseCase
SET ClientSftwrVer = #ClientSftwrVer,
CaseNbr = #CaseNbr,
CloseStatus = #CloseStatus,
CurrentlyEmployed = #CurrentlyEmployed,
systemdate = GETDATE(),
submit_user_id = #submit_user_id
WHERE EmpCloseCase_id = #EmpCloseCase_id
END
COMMIT TRANSACTION EmpCloseCase
END TRY
BEGIN CATCH
SET #EmpCloseCase_id=0
ROLLBACK TRANSACTION EmpCloseCase
END CATCH
RETURN #EmpCloseCase_id
END
Because that "OUTPUT" line is missing, it throws an error if I try to include <cfprocparam type="out" variable="empCloseCaseId"> in my cfstoredproc. Is there any way to access/store the value of this return variable #EmpCloseCase_id, using cfstoredproc, without having to add in that missing "OUTPUT" line or otherwise change the proc's code?
Change
RETURN #EmpCloseCase_id
to
SELECT #EmpCloseCase_id as emp_close_case_id
and in your cfstoredproc call, add
<cfprocresult name="foo">
This defines the variable foo as a query with a single row and a column emp_close_case_id.
<cfoutput>
#foo.emp_close_case_id#
</cfoutput>
EDIT: No way to access that data without properly declaring the output variable or returning a data set with a select statement. SQL Server docs: Return Data from a Stored Procedure

DB2 - how to call a stored procedure that returns a result set in another user defined table function

I have a db2 stored procedure that takes in some parameters, gets some data from somewhere and then returns a result set through a cursor.
Now I want to write a table function in db2, that will call this stored procedure, read from the result set and return the data in the result set as a table (eventually I want to use this table function in a join).
I would like to know if this is permitted in db2 (we're using DB2 v10.5), i.e. execute a stored procedure in a table function and fetch and read from the result set from the stored procedure. If so, what is the right syntax for calling the stored procedure and reading the result set inside a table function in db2? Thanks!
Yes, it's possible. See the example below.
--#SET TERMINATOR #
CREATE OR REPLACE PROCEDURE TEST_PROC(P_TABSCHEMA VARCHAR(128))
DYNAMIC RESULT SETS 1
READS SQL DATA
BEGIN
DECLARE C1 CURSOR WITH HOLD WITH RETURN FOR
SELECT TABSCHEMA, TABNAME, COLCOUNT
FROM SYSCAT.TABLES
WHERE TABSCHEMA=P_TABSCHEMA;
OPEN C1;
END#
--CALL TEST_PROC('SYSCAT')#
CREATE OR REPLACE FUNCTION TEST_PROC(P_TABSCHEMA VARCHAR(128))
RETURNS TABLE (
TABSCHEMA VARCHAR(128)
, TABNAME VARCHAR(128)
, COLCOUNT INT
)
READS SQL DATA
BEGIN
DECLARE SQLSTATE CHAR(5);
DECLARE V_TABSCHEMA VARCHAR(128);
DECLARE V_TABNAME VARCHAR(128);
DECLARE V_COLCOUNT INT;
DECLARE V1 RESULT_SET_LOCATOR VARYING;
CALL TEST_PROC(P_TABSCHEMA);
ASSOCIATE RESULT SET LOCATOR (V1) WITH PROCEDURE TEST_PROC;
ALLOCATE C1 CURSOR FOR RESULT SET V1;
L1: LOOP
FETCH C1 INTO V_TABSCHEMA, V_TABNAME, V_COLCOUNT;
IF SQLSTATE<>'00000' THEN LEAVE L1; END IF;
PIPE(V_TABSCHEMA, V_TABNAME, V_COLCOUNT);
END LOOP L1;
CLOSE C1;
RETURN;
END#
SELECT * FROM TABLE(TEST_PROC('SYSCAT'))#
You need to create the DB2 table-function as follows:
CREATE FUNCTION database_schema.function_name ( IN_PARTID VARCHAR(1000) )
RETURNS TABLE ( PARTNO CHAR(25), PARTDS CHAR(30), QUANTITY INT )
BEGIN
RETURN SELECT PARTNO , PARTDS , CASE WHEN QUANTITY > 0 THEN QUANTITY ELSE 0 END QUANTITY
FROM
(
SELECT PARTNO
,MAX(PARTDS) AS PARTDS
,SUM(QUANTITY) AS QUANTITY
FROM database_schema.table_name
WHERE 1=1
AND PARTID = (CAST(IN_PARTID AS INT))
GROUP BY PARTNO
) AA;
END;
Then invoke the table-function as join or straight SQL:
SELECT partno,partds,quantity
FROM TABLE(database_schema.function_name('parameter_1'))

Firebird stored procedure always returning zero

This is my stored procedure:
SET TERM ^ ;
CREATE PROCEDURE INSERT_ETYPE (
E_ID Integer,
E_NAME Varchar(20) CHARACTER SET NONE )
RETURNS (
NEW_ID Integer)
AS
declare variable addr varchar(20);
declare variable type smallint;
declare variable ord smallint;
declare variable cmd varchar(255);
declare variable answr varchar(255);
begin
insert into ETYPE
select * from ETYPE where ID=:e_id;
select max(ID) from ETYPE into :new_id;
update ETYPE set NAME = :e_name where ID = :new_id;
for
select ADDR,REGTYPE,ORD from ETYPEREGS
where ETYPE_ID=:e_id
into :addr,:type,:ord
do
begin
insert into ETYPEREGS
(ETYPE_ID,ADDR,REGTYPE,ORD)
values
(:new_id,:addr,:type,:ord);
end
for
select CMD,ANSWR,ORD,REGTYPE from ETYPESPECIAL
where ETYPE_ID=:e_id
into :cmd,:answr,:ord,:type
do
begin
insert into ETYPESPECIAL
(ETYPE_ID,CMD,ANSWR,ORD,REGTYPE)
values
(:new_id,:cmd,:answr,:ord,:type);
end
end^
SET TERM ; ^
This is my code in C++:
StoredProc_InsertEType->ParamByName("E_ID")->AsInteger = src_id;
StoredProc_InsertEType->ParamByName("E_NAME")->AsString = _name;
try
{
StoredProc_InsertEType->ExecProc();
new_id = StoredProc_InsertEType->ParamByName(L"NEW_ID")->AsInteger;
}
catch(EDBEngineError & e)
{
errors->Add(e.Message);
return false;
}
Variable new_id is always zero regardless of fact that table ETYPE is not empty. When I run command SELECT MAX(ID) FROM ETYPE from administration tool FlameRobin it returns correct number (~180). What should I do to obtain correct value of NEW_ID parameter?
you need to add
suspend;
in your sp
and query with
select * from your_sp
suspend explained
http://www.janus-software.com/fbmanual/manual.php?book=psql&topic=104
regards,

I cannot get the output parameter when use function import by Entity Framework

Here's my SQL Server stored procedure :
ALTER PROCEDURE [dbo].[SearchUser]
(#Text NVARCHAR(100),
#TotalRows INT = 0 OUTPUT)
AS
BEGIN
SELECT #TotalRows=1000
SELECT * from Users
END
And my C# code
using (var context = new TestDBEntities())
{
var outputParameter = new ObjectParameter("TotalRows", typeof(Int32));
context.SearchUser("", outputParameter);
Response.Write(outputParameter.Value);
}
However outputParameter.Value always is null.
Could anybody tell me why?
Output parameters filled by its actual values during the execution of the stored procedure.
But table-valued stored procedure actually get executed only in moment when you're trying to iterate resulting recordset, but not calling a wrapper method.
So, this DOES'T work:
using (var context = new TestDBEntities())
{
var outputParameter = new ObjectParameter("TotalRows", typeof(Int32));
context.SearchUser("", outputParameter);
// Paremeter value is null, because the stored procedure haven't been executed
Response.Write(outputParameter.Value);
}
This DOES:
using (var context = new TestDBEntities())
{
var outputParameter = new ObjectParameter("TotalRows", typeof(Int32));
// Procedure does not executes here, we just receive a reference to the output parameter
var results = context.SearchUser("", outputParameter);
// Forcing procedure execution
results.ToList();
// Parameter has it's actual value
Response.Write(outputParameter.Value);
}
When you're working with stored procedures what don't return any recordset, they execute immediately after a method call, so you have actual value in output parameter.
We had a simular issue due to defered excecution our unit tests failed. In short if you have a stored proc that does NOT return anything you need to be sure to set the response type as 'None' when set as 'None' it will be excecuted when called and not defered.
In case you return anything (E.g. Scalar type of String results) it will excecute it when you use the result even if that .Count() or .ToList() is outside of the method that contains the function call.
So try not to force excecution if not need, when needed it should excecute but be sure to declare it correctly or it might not work.
I have same problem before. The main reason I think that the entities framework has the bug in case the user stored procedure has output parameter and return a result set. For example:
ALTER PROCEDURE [dbo].[SearchTest]
(
#RowTotal INT = 0 OUTPUT,
#RowCount INT = 0 OUTPUT
)
AS
BEGIN
SET NOCOUNT ON
SELECT * FROM SomeThing
SELECT #RowTotal = 1233, #RowCount = 5343
END
However if you change the user stored procedure as following, you can get the output params
ALTER PROCEDURE [dbo].[SearchTest]
(
#RowTotal INT = 0 OUTPUT,
#RowCount INT = 0 OUTPUT
)
AS
BEGIN
SET NOCOUNT ON
SELECT #RowTotal = 1233, #RowCount = 5343
END
You can workaround as following:
ALTER PROCEDURE [dbo].[SearchTest]
AS
BEGIN
DECLARE #RowTotal INT, #RowCount INT
SET NOCOUNT ON
SELECT #RowTotal = 1233, #RowCount = 5343
SELECT #RowTotal AS RowTotal, #RowCount AS RowCount, s.*
FROM SomeThing s
END
If anybody has better solution, please tell me

Resources