I have a procedure that returns a list when requested - test_1.
I want to create a procedure that sends each value from a table type_cd_list to the procedure test_1 and returns a list, but I get an error:
An existing result set Cursor is opened from stored procedure
Code:
--calling procedures
CALL Pb_tmd.test_1('280');
--create table
CREATE VOLATILE TABLE type_cd_list
(
num_chn VARCHAR(10),
info_system_type_cd VARCHAR(10)
) ON COMMIT PRESERVE ROWS;
INSERT INTO type_cd_list ('12','280');
--procedure
REPLACE PROCEDURE Pb_tmd.test_2()
DYNAMIC RESULT SETS 1
BEGIN
DECLARE hc1 VARCHAR(10);
FOR
RepordPointer AS c_sptable CURSOR FOR
SELECT info_system_type_cd AS c_c1 FROM type_cd_list
DO
SET hc1 = RepordPointer.c_c1;
CALL Pb_tmd.test_1(:hc1);
END FOR;
ROLLBACK;
END;
Or is there another option to combine these 2 procedures? Below is the nested procedure code
REPLACE PROCEDURE Pb_tmd.test_1 (IN db_lst VARCHAR(100))
DYNAMIC RESULT SETS 1
BEGIN
DECLARE NumberInst VARCHAR(100);
DECLARE SQL_TEXT VARCHAR(3000);
DECLARE cur1 CURSOR WITH RETURN ONLY FOR S1;
SET SQL_TEXT = 'SELECT * FROM Pb_'||db_lst||'_tmd.LOAD_LOG';
PREPARE S1 FROM SQL_TEXT;
OPEN cur1;
END;
Related
What data type can I use to store all rows found by SELECT query?
CREATE OR REPLACE PROCEDURE handleFailedCalls(xNumber in varchar(10)) AS
result {DATA TYPE I WANT};
BEGIN
select * into result
from CALLS c1
where c1.status = 'fail'
END
/
One way is to use a REFCURSOR variable of OUT type.
CREATE OR REPLACE PROCEDURE handleFailedCalls(xNumber in varchar2,
p_result OUT SYS_REFCURSOR
) AS
BEGIN
OPEN p_result FOR select * from CALLS c1
where c1.status = 'fail'
END
/
Also, use VARCHAR2 instead of VARCHAR. It should be without the size, as procedure arguments with size won't compile.
The procedure can be called to receive the cursor into a local ref cursor variable.
DECLARE
res_cur SYS_REFCURSOR;
BEGIN
handleFailedCalls('Xnumber1', res_cur );
END;
/
Use BULK COLLECT, example:
DECLARE
TYPE emp_typ IS TABLE OF employees%ROWTYPE INDEX BY PLS_INTEGER;
all_employees emp_typ;
BEGIN
SELECT * BULK COLLECT INTO all_employees FROM employees;
A SELECT ... BULK COLLECT INTO statement can return multiple rows. You must set up collection variables to hold the results. You can declare associative arrays or nested tables that grow as needed to hold the entire result set.
I am trying to create a stored procedure, but I get this error
Expected tokens may include: "". LINE NUMBER=17. SQLSTATE=42601
My code:
CREATE OR REPLACE PROCEDURE FETCH_EMP_SP(IN V_EMP_NAME VARCHAR(100),IN V_EMP_DEPT VARCHAR(100))
DYNAMIC RESULT SETS 1
LANGUAGE SQL
BEGIN
DECLARE p_query_string VARCHAR(100);
IF ((V_EMP_NAME IS NOT NULL) AND (V_EMP_DEPT IS NOT NULL)) THEN
SET p_query_string = 'emp_name ='||V_EMP_NAME||' AND emp_dept='||V_EMP_DEPT||' WITH UR';
ELSEIF(V_EMP_DEPT IS NOT NULL) THEN
SET p_query_string = ' AND emp_dept='||V_EMP_DEPT||' WITH UR';
ELSE
SET p_query_string = ' WITH UR';
END IF;
DECLARE C1 CURSOR WITH RETURN TO CLIENT FOR SELECT emp_name,emp_no,emp_dept,emp_location from employee where status=1 p_query_string;
OPEN C1;
END#
should be executed successfully
Declarations and statements can’t follow in arbitrary order in a Compound SQL (compiled) statement
Cursor declarations must follow the variables declarations and must be followed by the SQL procedure statements.
So, place the cursor declaration after the variable declaration.
Moreover, there is a number of other errors in your code. Should be something like this:
CREATE OR REPLACE PROCEDURE FETCH_EMP_SP(IN V_EMP_NAME VARCHAR(100),IN V_EMP_DEPT VARCHAR(100))
DYNAMIC RESULT SETS 1
LANGUAGE SQL
BEGIN
DECLARE p_query_string VARCHAR(256);
DECLARE C1 CURSOR WITH RETURN TO CLIENT FOR S1;
IF ((V_EMP_NAME IS NOT NULL) AND (V_EMP_DEPT IS NOT NULL)) THEN
SET p_query_string = ' AND emp_name ='''||V_EMP_NAME||''' AND emp_dept='''||V_EMP_DEPT||''' WITH UR';
ELSEIF(V_EMP_DEPT IS NOT NULL) THEN
SET p_query_string = ' AND emp_dept='''||V_EMP_DEPT||''' WITH UR';
ELSE
SET p_query_string = ' WITH UR';
END IF;
SET p_query_string='SELECT emp_name,emp_no,emp_dept,emp_location from employee where status=1 '||p_query_string;
PREPARE S1 FROM p_query_string;
OPEN C1;
END#
String constants in the query text must be wrapped in single quotes. Don't do this if emp_dept is a numeric column.
I need to pass the parameter as table value for a stored procedure in SQL Server. How to handle this in Delphi?
As far as I know there in no simple way to pass Table parameters, using the components shipped with Delphi.
A workaround would be using a temporary table which can be used to fill a typed table variable.
Assuming your definition would look like this:
CREATE TYPE MyTableType AS TABLE
( ID int
, Text varchar(100) )
GO
CREATE PROCEDURE P_Table
#Tab MyTableType READONLY
AS
BEGIN
SET NOCOUNT ON;
Select * from #Tab -- dummy operation just return the dataset
END
GO
You could call the procedure like this:
var
i: Integer;
begin
// we create a temporary table since a table variable can obly be used for a single call
DummyDataset.Connection.Execute('Create Table #mytemp(ID int,Text varchar(100))');
DummyDataset.CommandText := 'Select * from #mytemp';
DummyDataset.Open;
for i := 0 to 10 do
begin
DummyDataset.Append;
DummyDataset.Fields[0].Value := i;
DummyDataset.Fields[1].Value := Format('A Text %d', [i]);
DummyDataset.Post;
end;
MyDataset.CommandText := 'Declare #mytemp as MyTableType '
+ 'Insert into #mytemp select * from #mytemp ' // copy data to typed table variable
+ 'EXEC P_Table #Tab = #mytemp';
MyDataset.Open;
DummyDataset.Connection.Execute('Drop Table #mytemp');
end
The sample downloadable from http://msftdpprodsamples.codeplex.com/wikipage?title=SS2008%21Readme_Table-Valued%20Parameters is written in C++ but could readily be translated to Delphi.
Once you have translated that code to Delphi, you can use something like the following to make the result set accessible via good ole ADO:
SourcesRecordset := CreateADOObject(CLASS_Recordset) as _Recordset;
RSCon := SourcesRecordset as ADORecordsetConstruction;
RSCon.Rowset := rowset;
LDataSet := TADODataSet.Create(nil);
try
// Only doing the first result set
LDataSet.Recordset := SourcesRecordset;
while not LDataSet.Eof do
begin
//... something
LDataSet.Next;
end;
finally
LDataSet.Free;
end;
Note that CreateADOObject is a private function in Data.Win.ADODB.pas but it's pretty trivial.
I have 2 procedures in same package.
I wish to use QOT_LST_M_QOT_PRE in QOT_LST_M_SEC_EXC_PRE. In QOT_LST_M_SEC_EXC_PRE I wish to find the argument - x_qot_id, call QOT_LST_M_QOT_PRE with this argument and also return it instead of the statement. Can I do it? How.
I mean something like
PROCEDURE QOT_LST_M_SEC_EXC_PRE (
i_sec_id IN NUMBER,
i_exc_id IN NUMBER,
o_recordset OUT SYS_REFCURSOR ) IS x_qot_id NUMBER(10);
------------------------------
BEGIN
---------------------------------------------------------------
--call a function instead of writing query from this function
open o_recordset for QOT_LST_M_QOT_PRE(x_qot_id, o_recordset);
----------------------------------------------------------------
END QOT_LST_M_SEC_EXC_PRE;
PROCEDURE QOT_LST_M_QOT_PRE
(
i_qot_id IN NUMBER,
o_recordset OUT SYS_REFCURSOR
--------------------------------
);
Sure you can. You can declare out parameters of type SYS_REFCURSOR and use them in your procedures, here is an example:
CREATE OR REPLACE PROCEDURE QOT_LST_M_QOT_PRE (i_qot_id IN NUMBER, THE_CURSOR OUT SYS_REFCURSOR) --Declare a sys_refcursor to be an out parameter, so it can be used outside
AS
BEGIN
OPEN THE_CURSOR FOR SELECT * FROM THE_TABLE WHERE X=i_qot_id;--Open the cursor
END;
CREATE OR REPLACE PROCEDURE QOT_LST_M_SEC_EXC_PRE (i_sec_id IN NUMBER, i_exc_id IN NUMBER)
AS
x_qot_id NUMBER(10); --Test param
RESULT_CURSOR SYS_REFCURSOR;--The cursor that will hold the opened cursor in QOT_LST_M_QOT_PRE procedure
SOMEVARIABLE VARCHAR2(10);--Test variables to hold results of cursor
BEGIN
QOT_LST_M_QOT_PRE(1,RESULT_CURSOR);--Procedure will open RESULT_CURSOR
LOOP --Loop cursor
FETCH RESULT_CURSOR INTO SOMEVARIABLE;
EXIT WHEN RESULT_CURSOR%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('READ :'||SOMEVARIABLE);
END LOOP;
CLOSE RESULT_CURSOR;--Close the opened cursor
END;
I wanted to know how to insert into a table using stored procedures in DB2 using SQL.
I have created a table as follows:
create table ADCLIBT.Itest
(ITNBR CHAR(15) CCSID 65535 NOT NULL DEFAULT '');
This table contains a list of items. Using this list I want to insert various other fields to another table. But, just for example sake, let's say I just want to insert these values one by one using cursors.
I have written the stored procedure as follows:
create procedure ADCLIBT.itest1()
LANGUAGE SQL
BEGIN
DECLARE itemno char(15);
DECLARE END_TABLE INT DEFAULT 0;
DECLARE not_found CONDITION FOR SQLSTATE '20000';
DECLARE c CURSOR FOR
select ITNBR from ADCLIBT.ITEMAT;
DECLARE CONTINUE HANDLER FOR not_found
SET END_TABLE = 1;
open c;
fetch from c into itemno;
WHILE END_TABLE = 0 DO
insert into ADCLIBT.ITEST
(ITNBR)
values
(select a.ITNBR from ADCLIBT.ITEMAT a where ITNBR=itemno GROUP BY a.ITNBR);
END WHILE;
Close c;
END;
This is giving me an infinite loop. Can anyone please tell me how do I stop the infinite loop and insert these records. I want to use the cursor because I want to further use itemno to compare and get single results.
You are opening the cursor but not feching in the while, you must do a fetch in the while of the cursor. Here an example from the IBM documentation.
CREATE PROCEDURE sum_salaries(OUT sum INTEGER) LANGUAGE SQL
BEGIN
DECLARE SQLSTATE CHAR(5) DEFAULT '00000';
DECLARE p_sum INTEGER;
DECLARE p_sal INTEGER;
DECLARE c CURSOR FOR SELECT SALARY FROM EMPLOYEE;
SET p_sum = 0;
OPEN c;
FETCH FROM c INTO p_sal;
WHILE(SQLSTATE = '00000') DO
SET p_sum = p_sum + p_sal;
FETCH FROM c INTO p_sal;
END WHILE;
CLOSE c;
SET sum = p_sum;
END%