TORA Execute Package Procedure with OUT REF CURSOR - oracle

I'm trying to execute a Package Procedure that has a couple in parameters and a REF CURSOR out parameter but can't seem to figure it out for TORA (my SQL IDE)
Here is a contrived example of a procedure I'd like to execute and see the cursor for:
PROCEDURE get_peeps_in_city ( pi_city IN varchar(100), po_recordset OUT REF CURSOR )
IS
BEGIN
OPEN po_recordset
FOR Select Id,
FName,
LName
FROM People
WHERE City like '%' || pi_city || '%'
END;
Here is what I've tried so far:
DECLARE
v_cursor REF CURSOR;
BEGIN
execute PKG_PEEPS.get_peeps_in_city('Chicago', v_cursor);
END
The error that I get is something along the lines of:
PLS-00103: Encountered the symbol "END" when expecting one of the
following:
begin function package pragma procedure subtype type use form current
cursor

You're probably looking for something like this:
DECLARE
v_cursor SYS_REFCURSOR;
v_Id NUMBER;
v_FName VARCHAR2(200);
v_LName VARCHAR2(200);
BEGIN
PKG_PEEPS.get_peeps_in_city('Chicago', v_cursor);
LOOP
FETCH v_cursor INTO v_Id, v_FName, v_LName;
EXIT WHEN v_cursor%NOTFOUND;
-- do something with v_Id, v_FName, v_LName
END LOOP;
CLOSE v_cursor;
END;
/
Update:
You probably would like that the result of your query is displayed in your IDE as if you had run the SELECT statement directly. This is not going to happen with the above code and I don't know of any code that could achieve that (unless you install a specific table function).
The best thing you can do is output the retrieved data in the loop (using DBMS_OUTPUT.PUT_LINE).

Related

How can a stored procedure be executed in Oracle with in and out parameters?

Here's my stored procedure:
CREATE OR REPLACE PROCEDURE STATS_SD
(
P_ID IN NUMBER,
PRC OUT SYS_REFCURSOR
)
IS
BEGIN
OPEN PRC FOR
SELECT
ID,
SESID
FROM RESPONSES
WHERE ID IN (P_ID)
END;
When I try to execute it using
EXEC EXAM_STATS_STUDENTS_SD('6901');
I get the following error:
PLS-00306: wrong number or types of arguments in call to 'STATS_SD'
Do you have any ideas why?
Here is an example using an OUT parameter that is a sys_refcursor. Note that I close the cursor in the pl/sql block that uses it (which is important!):
create or replace procedure get_data(o_cur OUT SYS_REFCURSOR) as
begin
OPEN o_cur FOR
select * from emp;
end;
And using the get_data procedure:
declare
l_cur sys_refcursor;
l_row emp%rowtype;
begin
get_data(l_cur);
LOOP
fetch l_cur
into l_row;
exit when l_cur%notfound;
-- do something with l_row here
END LOOP;
close l_cur;
end;
You are passing a wrong datatype to your procedure.
According to your declaration a NUMBER is expected:
P_ID IN NUMBER
However, you pass a VARCHAR2 in your exec command:
EXEC EXAM_STATS_STUDENTS_SD('6901');
Note the '' around the value.
Try calling this instead:
EXEC EXAM_STATS_STUDENTS_SD(6901);
Apart from that you are missing the second parameter completely.

PL/SQL - Cursor. Can't iterate through table (varchar argument)

I created a procedure to calculate the hashcode of a record (complete line of a table) and then update a column with the calculated hashcode number.
Here's my code at this point (which is based on some info I manage to gather from Google):
CREATE OR REPLACE PROCEDURE calcHashCode (inputTableString IN varchar2) IS
c_data varchar2(3000); --QUERY
c_cursor sys_refcursor; --CURSOR
c_record inputTableString%rowtype; -- Problem is here
BEGIN
c_data := 'SELECT * FROM ' || inputTableString;
OPEN c_cursor for c_data;
LOOP
FETCH c_cursor INTO c_record;
EXIT WHEN c_cursor%notfound;
-- will do stuff here with the records
dbms_output.put_line('stuff');
END LOOP;
CLOSE c_cursor;
END;
/
SHOW ERRORS
4/13 PLS-00310: with %ROWTYPE attribute, 'INPUTTABELA' must name a table, cursor or cursor-variable
4/13 PL/SQL: Item ignored
11/25 PLS-00320: the declaration of the type of this expression is incomplete or malformed
11/5 PL/SQL: SQL Statement ignored
So, my idea (for the final stage of the procedure) is to iterate through out the records, build a string with and then calculate the hashcode. After that, I'll run the update instruction.
The thing is at this point using a varchar as an argument and I'm not being able to iterate through the table in order to get my concatenate records.
dynamic cursors are the ugliest...
the problem is with that section:
c_data varchar2(3000); --QUERY
c_cursor sys_refcursor; --CURSOR
c_record inputTableString%rowtype;
i used something like this:
TYPE t_data IS REF CURSOR;
cr_data t_data;
cr_data_rec inputTableString%ROWTYPE; --that table need to be exists in compile time
the rest are good i think
Have you considered pushing the whole declaration and loop into an anonymous block that will then get executed by EXECUTE IMMEDIATE? You can then simplify your looping construct to a simple FOR loop too.
I'm away from my database at the moment, so excuse any syntax glitches, but something like
CREATE OR REPLACE PROCEDURE calcHashCode (inputTableString IN varchar2) IS
c_data varchar2(30000); --QUERY
BEGIN
c_data := '
BEGIN
FOR aRec IN
(SELECT * FROM ' || inputTableString ||' )
LOOP
--do your stuff
END LOOP;
END';
execute immediate c_Data;
END;
/
It may not be pretty, and your "Stuff" may not easily be able to be fit into this construct, but it IS feasible
You can do all this kind of stuff with PL/SQL package DBMS_SQL, however it is definitely not for beginners and you should start with something easier.
Examples for DBMS_SQL

How to build a dynamic PLSQL query to fetch records?

I am trying to create a stored procedure in Oracle and make a dynamic query work to get a bunch of records. I have read many examples but so far I can't get this to work unless I do this:
CREATE OR REPLACE PROCEDURE GiveMeResultSet(
v_par1 IN CHAR,
v_par2 IN CHAR,
v_par3 IN CHAR,
v_par4 IN VARCHAR2,
v_par5 IN VARCHAR2,
v_par6 IN VARCHAR2,
cur_typ OUT SYS_REFCURSOR)
IS
BEGIN
OPEN cur_typ FOR 'select * from complex_query';
--CLOSE cur_typ;
END;
And I am executing it this way:
var c refcursor;
execute GiveMeResultSet(null,null,null,null,null,null,:c);
print c;
This way I get the header names and the records from the query, but I am not closing the cursor that is fetching the results. If I close it then I get nothing at all. I guess leaving it open could cause some kind of memory leak problem at some point.
I have seen similar cases in Oracle documentation where they do something like this:
sql_stmt := 'SELECT * FROM emp';
OPEN emp_cv FOR sql_stmt;
LOOP
FETCH emp_cv INTO emp_rec;
EXIT WHEN emp_cv%NOTFOUND;
-- process record
END LOOP;
CLOSE emp_cv;
But I have no clue what goes on the "process record" part of the code which would allow to get the whole set of records at the end, plus that my record has a complex structure that doesn't fit with a fixed set of fields as in a table.
Can you please show me the proper way to do this?.
Thanks a lot.
ok CodeRoller, here is my sample code for a unspecified ref cursor:
Code of the Function which returns the ref cursor:
create or replace function test_ref_cursor(pi_sql_statement in varchar2) return SYS_REFCURSOR is
result_cursor SYS_REFCURSOR;
begin
open result_cursor for pi_sql_statement;
return result_cursor;
end;
Now, in the next step I use this function to get data from v$parameter:
declare
type t_my_cursor is ref cursor;
my_cursor t_my_cursor;
l_rec v$parameter%rowtype;
begin
my_cursor := test_ref_cursor('select * from v$parameter');
loop
fetch my_cursor into l_rec;
exit when my_cursor%notfound;
dbms_output.put_line(l_rec.name || ' = ' || l_rec.value);
end loop;
close my_cursor;
end;
Take care, to close the ref-cursor!

Oracle SQL Developer PL/SQL return an array

Devs,
I've searched everywhere I can, but I could not find solution to this simple problem.
Situation:
I need to write a procedure where it takes a column name as the input and return all the distinct values present in that column as output. And then I have to use this procedure in some c# code.
In MS server, it is very easy as it will directly give the set of results unlike in PL/SQL.
Script I could write (which is not giving me the result I need):
CREATE OR REPLACE
PROCEDURE GetCol(PARAM IN STRING, recordset OUT sys_refcursor)
AS
BEGIN
OPEN recordset FOR
SELECT DISTINCT(PARAM)
FROM my_table;
END
;
When I try to check the data in the recordset using this code:
DECLARE
l_cursor SYS_REFCURSOR;
l_sname VARCHAR2(50);
BEGIN
GetCol('col_name',l_cursor);
LOOP
FETCH l_cursor INTO l_sname;
EXIT WHEN l_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(l_sname);
END LOOP;
CLOSE
Can someone help me with this code please.
You can also open a ref_cursor for a string value. Please take a look at this:
CREATE OR REPLACE PROCEDURE GetCol(PARAM IN VARCHAR2, recordset OUT sys_refcursor)
AS
QRY varchar2(100);
BEGIN
QRY := 'SELECT DISTINCT '||PARAM||' FROM my_table';
OPEN recordset FOR QRY;
END;
Then:
DECLARE
l_cursor SYS_REFCURSOR;
l_sname VARCHAR2(50);
BEGIN
GetCol('col_name',l_cursor);
LOOP
FETCH l_cursor INTO l_sname;
EXIT WHEN l_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(l_sname);
END LOOP;
END;
Your problem is caused by ambiguity about what PARAM is in the procedure's SELECT statement:
CREATE OR REPLACE
PROCEDURE GetCol(PARAM IN STRING, recordset OUT sys_refcursor)
AS
BEGIN
OPEN recordset FOR
SELECT DISTINCT(PARAM) -- Ambiguity here
FROM my_table;
END;
Does PARAM refer to the table column or to the first parameter of the procedure? Oracle has assumed the parameter. You can explicitly say which like this:
SELECT DISTINCT(my_table.PARAM)
FROM my_table;
You could if appropriate (it probably isn't here) specify the procedure parameter instead:
SELECT DISTINCT(GetCol.PARAM)
FROM my_table;
Generally this is best avoided by:
always using table aliases in column references select statements, and
having a standard for parameter names that makes them less likely to clash e.g. P_PARAM.

expression of wrong type oracle error

I am trying to execute the below plsql program, but facing expression of wrong type. Could anyone let me know what might be the error?
CREATE OR REPLACE PROCEDURE CLN_TBL (CTRLM IN VARCHAR2, CTG IN VARCHAR,SBCT IN NUMBER, RTDT IN NUMBER )
AS
V_SQL VARCHAR(2000);
V_TABLE VARCHAR(30);
CURSOR TBL_CUR
IS
SELECT TGT_TABLE_NAME FROM ODS_USER.CLNP WHERE CONTROLM=CTRLM AND APPL_CTGY=CTG AND APPL_SUB_CTGY= SBCT;
L_TGT_TABLE_NAME TBL_CUR%ROWTYPE;
BEGIN
OPEN TBL_CUR;
LOOP
FETCH TBL_CUR INTO L_TGT_TABLE_NAME;
V_TABLE:= L_TGT_TABLE_NAME ;
EXIT WHEN TBL_CUR%NOTFOUND;
V_SQL:='DELETE FROM '||V_TABLE||' WHERE RPT_DT_ID'||'=:1';
EXECUTE IMMEDIATE V_SQL using RTDT;
END LOOP;
COMMIT;
CLOSE TBL_CUR;
END;
As Exhausted said you cant assign row variable to varchar so You should take TGT_TABLE_NAME from row variable, like below should work;
CREATE OR REPLACE PROCEDURE CLN_TBL (CTRLM IN VARCHAR2, CTG IN VARCHAR,SBCT IN NUMBER, RTDT IN NUMBER )
AS
V_SQL VARCHAR(2000);
V_TABLE VARCHAR(30);
CURSOR TBL_CUR
IS
SELECT TGT_TABLE_NAME FROM ODS_USER.CLNP WHERE CONTROLM=CTRLM AND APPL_CTGY=CTG AND APPL_SUB_CTGY= SBCT;
L_TGT_TABLE_NAME TBL_CUR%ROWTYPE;
BEGIN
OPEN TBL_CUR;
LOOP
FETCH TBL_CUR INTO L_TGT_TABLE_NAME;
V_TABLE:= L_TGT_TABLE_NAME.TGT_TABLE_NAME ;
EXIT WHEN TBL_CUR%NOTFOUND;
V_SQL:='DELETE FROM '||V_TABLE||' WHERE RPT_DT_ID'||'=:1';
EXECUTE IMMEDIATE V_SQL using RTDT;
END LOOP;
COMMIT;
CLOSE TBL_CUR;
END;

Resources