Open cursor for select statement with Input variables - stored-procedures

I have two cursors in my package. the first Cursor does not have an input parameter so I have Successfully Opened it like this:
OPEN c1 for
SELECT foracid,
acct_name,
addr_1,
addr_2,
sol_desc,
city_code,
gam.FUTURE_UN_CLR_BAL_AMT
FROM tbaadm.gam,
tbaadm.sol
WHERE gam.sol_id = sol.sol_id
AND schm_type IN ('CAA','ODA','LAA')
AND schm_code NOT IN ('CTSTF');
CLOSE c1;
But My second Cursor has an input Parameter and I can't do:
OPEN c2 (vMyName varchar2) for select .....
because of this error:
Found Varhcar2 Expecting : ) and -or...
Can I really Open This cursor this way or what should I do?

You can just do the following:
create or replace procedure proc (c2 OUT SYS_REFCURSOR) AS
vMyName varchar2(100);
begin
vMyName := 'Some Value';
open c2 for
select col1, col2, col3
from tab1
where val = vMyName;
end;

Related

How to use cursor results in a query in stored procedure

I am trying to get the variable (ACTIVE_INVENTORY) value from sql query dynamically and use it in further below queries. But it seems to be giving error.
Please suggest how could a variable be used in following query.
Thanks
create or replace procedure sp()
returns table (vin varchar, listing_date date, sale_date date, active_inventory boolean)
language sql
as
$$
declare
select_query varchar;
SOLD_THRESHOLD_DATE date;
c1 cursor for select max(sale_date) from TBL;
res resultset;
begin
open c1;
fetch c1 into SOLD_THRESHOLD_DATE;
select_query := 'select vin,listing_date,sale_date,
case when 60 >= DATEDIFF(Day,sale_date,SOLD_THRESHOLD_DATE) then 1 else 0 end as active_inventory from
TBL limit 10';
res:= (execute immediate : select_query);
close c1;
return table(res);
end;
$$;
call sp();
Uncaught exception of type 'STATEMENT_ERROR' on line 13 at position 9 : SQL compilation error: error line 2 at position 41 invalid identifier 'SOLD_THRESHOLD_DATE'
Parametrizing the query:
select_query := 'select vin,listing_date,sale_date,
case when 60>=DATEDIFF(Day,sale_date,?) then 1 else 0 end as active_inventory
from TBL limit 10';
res:= (execute immediate :select_query using (SOLD_THRESHOLD_DATE) );

Dynamic Insert through Teradata Stored procedure

I am trying to run Insert statement to load data into table using Teradata Stored procedure. Here I am trying to Input Table Name, Databasename as Parameter. My stored procedure compiled and ran well. But its not inserting any data into table. Could someone please help me with this. Below is the query I am using..
REPLACE PROCEDURE DB.TEST_SP
(
IN SRC_DB_NM VARCHAR(30)
, IN SRC_TBL_NM VARCHAR(30)
, OUT MESSAGE VARCHAR(200)
)
DYNAMIC RESULT SETS 1
BEGIN
DECLARE QUERY1 VARCHAR(200);
DECLARE RESULT1 VARCHAR(200);
DECLARE REC_COUNT INTEGER DEFAULT 0;
DECLARE STATUS CHAR(10) DEFAULT '00000';
DECLARE C1 CURSOR FOR S1;
DECLARE EXIT HANDLER FOR SQLEXCEPTION,SQLWARNING
BEGIN
SET STATUS = SQLCODE;
IF(TRIM(STATUS)) = '3807' THEN
SET MESSAGE = 'PASSED TABLE '||SRC_DB_NM||'.'||SRC_TBL_NM||' DOES NOT EXIST';
ELSE
SET MESSAGE = 'LOADED';
END IF;
END;
BEGIN
SET QUERY1 ='INSERT INTO TABLE1 SELECT ColX , count(*) from DB.table2 where Col in ( SELECT Col1 FROM ' || SRC_DB_NM || '.' || SRC_TBL_NM || ' where ColY = 999 ) group by 1;' ;
EXECUTE IMMEDIATE QUERY1;
PREPARE S1 FROM QUERY1;
OPEN C1 USING SRC_DB_NM,SRC_TBL_NM;
FETCH C1 INTO RESULT1;
SET MESSAGE = RESULT1;
END;
END;

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'))

Oracle stored procedure combine results

I am working on the following Oracle (PL/SQL) stored procedure:
Procedure myProc(idParam IN Number, RESULT OUT SYS_REFCURSOR)
IS
BEGIN
FOR myMetaData in (select status, idData from Table1 where id=idParam)
LOOP
IF myMetaData.status='test1'
SELECT column1, column2, column3 from Table2 where cond1=cond2;
ELSE
SELECT column1, column2, column3 from Table2 where column4=
(select column4 from.....);
END IF;
END LOOP;
END myProc;
Assuming above is my code now I need to return combined results from both IF clause select statement and Else clause. I tried with dbms_sql.return_result(); but it didn't help.
How can I combine both result sets and return the value?
There are many ways to achieve your requirement however i would prefer to use a table to achieve your requirement. See below:
--Create a table to hold your result of if clause
Create table Rslt (col1 number,col2 number, col3 number);
/
--Use sysrefcursor to get the final result out of the table
Procedure myProc(idParam IN Number, RESULT OUT SYS_REFCURSOR)
IS
BEGIN
FOR myMetaData in (select status, idData from Table1 where id=idParam)
LOOP
IF myMetaData.status='test1'
insert into rslt SELECT column1, column2, column3 from Table2 where cond1=cond2;
ELSE
insert into rslt SELECT column1, column2, column3 from Table2 where column4=
(select column4 from.....);
END IF;
END LOOP;
Open result for select * from rslt;
END myProc;
Another apporach could be Object Oriented using a Object having table columns. See below:
Create type rslt is object
(col1 number,
col2 number,
col3 number
);
Create type var_rslt is table of rslt ;
Procedure myProc(idParam IN Number, V_RESULT OUT SYS_REFCURSOR)
IS
v_rslt1 var_rslt:=var_rslt();
v_rslt2 var_rslt:=var_rslt();
v_rslt3 var_rslt:=var_rslt();
v_rslt4 var_rslt:=var_rslt();
BEGIN
FOR myMetaData in (select status, idData from Table1 where id=idParam)
LOOP
IF myMetaData.status='test1'
SELECT rslt(column1, column2, column3) bulk collect into v_rslt1 from Table2 where cond1=cond2;
v_rslt2:=v_rslt2 Multiset union all v_rslt1;
ELSE
SELECT rslt(column1, column2, column3) bulk collect into v_rslt13 from Table2 where column4= (select column4 from.....);
v_rslt4:=v_rslt4 multiset union all v_rslt13;
END IF;
END LOOP;
v_rslt2 := v_rslt2 multiset union all v_rslt4;
OPEN V_RESULT FOR SELECT * FROM table( v_rslt2 );
END myProc;
Demo:
Table Preparation:
Create table Table1 (id number, status varchar2(10));
/
Insert into table1 values(1,'test1');
Insert into table1 values(2,'test2');
Create table Table2 (id number,column1 number, column2 number, column3 number);
/
insert into table2 values(1,10,20,30);
insert into table2 values(1,70,60,50);
insert into table2 values(1,20,40,30);
insert into table2 values(2,80,40,20);
insert into table2 values(2,60,20,10);
Create type rslt is object
(col1 number,
col2 number,
col3 number
);
Create type var_rslt is table of rslt ;
Procedure:
CREATE OR REPLACE Procedure myProc(idParam IN Number, V_RESULT OUT sys_refcursor)
IS
v_rslt1 var_rslt:=var_rslt();
v_rslt2 var_rslt:=var_rslt();
v_rslt3 var_rslt:=var_rslt();
v_rslt4 var_rslt:=var_rslt();
BEGIN
FOR myMetaData in (select status, id from Table1)
LOOP
IF myMetaData.status='test1' then
SELECT rslt(column1, column2, column3) bulk collect into v_rslt1 from Table2 where id=myMetaData.id;
v_rslt2:=v_rslt2 Multiset union all v_rslt1;
ELSE
SELECT rslt(column1, column2, column3) bulk collect into v_rslt3 from Table2 where id=myMetaData.id;
v_rslt4:=v_rslt4 multiset union all v_rslt3;
END IF;
END LOOP;
v_rslt4 := v_rslt4 multiset union all v_rslt2;
open V_RESULT for Select * from table(v_rslt4);
END myProc;
Execution:
DECLARE
var sys_refcursor;
var1 NUMBER;
var2 NUMBER;
var3 NUMBER;
BEGIN
myProc(1, var);
LOOP
FETCH var INTO var1,var2,var3;
EXIT WHEN var%notfound;
dbms_output.put_line(var1);
END LOOP;
END;
OUTPUT:
SQL> /
anonymous block completed
80
60
10
70
20
Note: This solution will work on Oracle 11g and onward versions. Incase you are working on lower version of Oracle, then you need to modify the Object definition as below:
Create type rslt is object
(col1 number,
col2 number,
col3 number,
map member function mem return number);
This is due to a bug in Oracle 10g while using MULTISET operator.
Read more about the bug at http://raajeshwaran.blogspot.com/2010/07/pls-00801-internal-error-assert-at-file.html

DB2 - Declare Cursor in Stored Procedure

I've found this "DECLARE CURSOR" Statement on WWW:
CREATE OR REPLACE PROCEDURE "APART21C"."FIND_VALID_ARZTNRN"
(OUT NoOfRows BIGINT)
RESULT SETS 1
LANGUAGE SQL
SPECIFIC SQL140905135133600
BEGIN
DECLARE myARZTNR CHAR(7);
DECLARE END_TABLE INT DEFAULT 0
;
DELETE FROM APART21C.TMP_LANR07_CHECK
;
DECLARE C1 CURSOR FOR
SELECT DISTINCT Arztnr
FROM APART21C.DMP_LEV_TMP
;
DECLARE CONTINUE HANDLER FOR NOT FOUND
SET END_TABLE = 1
;
OPEN C1
;
FETCH C1 INTO myARZTNR
;
WHILE END_TABLE = 0 DO
INSERT INTO APART21C.TMP_LANR07_CHECK
SELECT * FROM TABLE(APART21C.CHECK_ARZTNR_BY_CHECKSUM(myARZTNR)) AS ARZTNRCHECK;
SET NoOfRows = NoOfRows + 1;
FETCH C1 INTO myARZTNR;
END WHILE
;
CLOSE C1
;
END
Errormessage is
"DB2 SQL Error: SQLCODE=-104, SQLSTATE=42601, SQLERRMC=<cursor declaration>;;<SQL statement>"
Need your help, please
I'm a beginner of db2, I've more experience in MS SQL Server.
The statement "SELECT * FROM TABLE(..." calls a function which returns a table.
Problem with the below code
DECLARE C1 CURSOR FOR
SELECT DISTINCT Arztnr
FROM APART21C.DMP_LEV_TMP
I have changed as below and it executed
DECLARE C1 CURSOR WITH HOLD FOR
SELECT Arztnr FROM DMP_LEV_TMP;

Resources