DECLARE
l_rcursor SYS_REFCURSOR;
BEGIN
OPEN l_rcursor FOR SELECT * FROM all_users;
dbms_output.put_line(l_rcursor%ROWCOUNT);
END;
This is long code so i cant use the cursor inside the declare portion. Here i need the count of rows fetched. I cant use rowtype because it is a join query.
Well, you can not.
There's a way to find out whether cursor contains anything (using the %NOTFOUND attribute), such as
SQL> declare
2 l_rcursor sys_refcursor;
3 l_rec all_users%rowtype;
4 begin
5 open l_rcursor for select * From all_users
6 where 1 = 2; --> will cause nothing to be returned
7
8 -- check whether there is (or is not) anything there
9 fetch l_rcursor into l_rec;
10 if l_rcursor%notfound then
11 dbms_output.put_line('There''s nothing there');
12 end if;
13 end;
14 /
There's nothing there
PL/SQL procedure successfully completed.
SQL>
but you can't know how many rows it'll return, which means that you'll have to count number of rows elsewhere (probably code that uses what you wrote in your question).
Possible duplicate to counting rows from a cursor in pl/sql
You can also just use COUNT in your cursor query to solve your problem, sample code below
DECLARE
l_rcursor SYS_REFCURSOR;
v_count NUMBER;
BEGIN
OPEN l_rcursor FOR SELECT COUNT(1) FROM (SELECT * FROM all_users);
-- OR
-- OPEN l_rcursor FOR SELECT COUNT(1) FROM all_users;
FETCH l_rcursor INTO v_count;
dbms_output.put_line(v_count);
END;
/
Related
working with oracle sql and oracle service bus.
I have a problem with closing the connection.
An example of a simple procedure I use is the following :
create or replace procedure getempdata(
v_id in number,
q out sys_refcursor
)
as
begin
open q for select * from employees where id = v_id;
end;
I need a way to close the cursor after getting the data from it.
but if I use close Q; , I can't read the data returned in service bus adapter .
The question is :
Is there a way to close the cursor (for memory management) from service bus after reading it?
And if there is not, Is there a way to do so from the procedure with returning the data as output?
Note: I don't call the procedure from sql code, so I can close it. I call it as a webservice using service bus webservice that calls the procedure by a database adapter; so I need the data returned in service bus
You'd close it from the caller.
Your procedure (adjusted to Scott's sample schema):
SQL> create or replace procedure getempdata(
2 v_id in number,
3 q out sys_refcursor
4 )
5 as
6 begin
7 open q for select ename from emp where deptno = v_id;
8 end;
9 /
Procedure created.
Let's call it:
SQL> set serveroutput on
SQL> declare
2 l_rc sys_refcursor;
3 l_ename emp.ename%type;
4 begin
5 getempdata(10, l_rc); --> procedure is called here
6 loop
7 fetch l_rc into l_ename;
8 exit when l_rc%notfound;
9 dbms_output.put_line(l_ename);
10 end loop;
11 close l_rc; --> cursor is closed here
12 end;
13 /
CLARK
KING
MILLER
PL/SQL procedure successfully completed.
SQL>
Yes, close it once you have read from it (or if an exception occurs that prevents reading from it) using the CLOSE statement.
DECLARE
v_cur SYS_REFCURSOR;
v_row EMPLOYEES%ROWTYPE;
BEGIN
-- call the procedure
getempdata(1, v_cur);
-- read the rows
LOOP
FETCH v_cur INTO v_row;
EXIT WHEN v_cur%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_row.id);
END LOOP;
-- close the cursor
CLOSE v_cur;
EXCEPTION
WHEN OTHERS THEN -- Handling OTHERS is bad practice, normally you should be more specific
IF v_cur%ISOPEN THEN
CLOSE v_cur;
END IF;
END;
/
fiddle
I'm trying to send variable schema name to cursor via procedure input
Here is my lame try, but you can see what I want to do:
CREATE OR REPLACE PROCEDURE HOUSEKEEPING
(SCHEMANAME in varchar2)
IS
CURSOR data_instances IS select table_name
from SCHEMANAME.table_name where TYPE='PERMANENT' and rownum<200 ;
BEGIN
DBMS_OUTPUT.PUT_LINE(SCHEMANAME);
END;
/
it throws expected
PL/SQL: ORA-00942: table or view does not exist
is there lawful way to make schema name work as variable? thanks
There is a way; you'll need some kind of dynamic SQL because you can't use schema (or object) names like that. For example, you could use refcursor instead.
Sample table:
SQL> create table table_name as
2 select 'EMP' table_name, 'PERMANENT' type from dual union all
3 select 'DEPT' , 'TEMPORARY' from dual union all
4 select 'BONUS' , 'PERMANENT' from dual;
Table created.
Procedure; note the way I composed SELECT statement first (so that I could display it and check whether it is correct), and then used it in OPEN. Loop is here to ... well, loop through the cursor. I'm just displaying table names I found - you'd probably do something smarter.
SQL> create or replace procedure housekeeping (par_schemaname in varchar2)
2 is
3 l_str varchar2(500);
4 l_rc sys_refcursor;
5 l_table_name varchar2(30);
6 begin
7 l_str := 'select table_name from ' ||
8 dbms_assert.schema_name(upper(par_schemaname)) ||
9 '.table_name where type = ''PERMANENT'' and rownum < 200';
10 open l_rc for l_str;
11
12 loop
13 fetch l_rc into l_table_name;
14 exit when l_rc%notfound;
15
16 dbms_output.put_line(l_table_name);
17 end loop;
18 close l_rc;
19 end;
20 /
Procedure created.
Testing:
SQL> set serveroutput on
SQL> exec housekeeping('SCOTT');
EMP
BONUS
PL/SQL procedure successfully completed.
SQL>
I am trying to dynamically resolve the value from cursor something like below.
create or replace
PROCEDURE test(
PI_JANUS_ID IN VARCHAR2,
PO_dummy out Types.CursorType
)AS
PO_ACTUALCUROSR Types.CursorType;
cur_row tab%ROWTYPE;
val1 varchar2(100);
val2 varchar2(200);
BEGIN
open PO_ACTUALCUROSR for select * from tab;
LOOP
FETCH PO_ACTUALCUROSR into cur_row;
EXIT WHEN PO_ACTUALCUROSR%NOTFOUND;
val1 := 'TNAME';
SELECT 'cur_row.'||val1 INTO val2 FROM DUAL;
dbms_output.put_line('Column Value ' || val2);
END LOOP ;
CLOSE PO_ACTUALCUROSR;
END;
Here if you see I have to call cur_row. to get the value but here I have the column name in a variable (val1). So how will I take the value from the cursor.
If I execute the above block I would see "cur_row.TNAME" but I actually need the value in the cursor.
Is there a way of doing this.
Any help is very much appreciated.
just do
BEGIN
open PO_ACTUALCUROSR for select * from tab;
LOOP
FETCH PO_ACTUALCUROSR into cur_row;
EXIT WHEN PO_ACTUALCUROSR%NOTFOUND;
val2 := cur_row.tname;
dbms_output.put_line(val2);
END LOOP ;
CLOSE PO_ACTUALCUROSR;
end;
or
dbms_output.put_line(cur_row.tname);
directly will also work.
p.s. your variable
val2 varchar2(200);
is better as
val2 tab.tname%type;
if you're saying you need to dynamically pull columns without knowing the column name ahead of time you'd have to use dynamic sql, and as you're using a pl/sql array, we need to put that in a package spec so that we can reference it (as you cannot pass pl/sql only types into dynamic SQL).
SQL> create table tab(id number, col1 varchar2(10));
Table created.
SQL> insert into tab values (1, 'a');
1 row created.
SQL> commit;
Commit complete.
SQL> create package global_var
2 as
3 cur_row tab%rowtype;
4 end;
5 /
Package created.
SQL> declare
2 po_actualcurosr sys_refcursor;
3 val1 varchar2(10) := 'COL1';
4 val2 tab.col1%type;
5 begin
6 open po_actualcurosr for select * from tab;
7
8 loop
9 fetch po_actualcurosr into global_var.cur_row;
10 exit when po_actualcurosr%notfound;
11 execute immediate 'begin :a := global_var.cur_row.'||dbms_assert.simple_sql_name(val1)||'; end;' using out val2;
12 dbms_output.put_line(val2);
13 end loop ;
14 close po_actualcurosr;
15 end;
16 /
a
PL/SQL procedure successfully completed.
Im new to cursors in Oracle. I have a piece of SQL that is contained in a variable. I want to open a cursor with this sql. How do I do this? Seems simple but all the examples I find just have the sql typed directly below the "open cursor_name for" statement.
Here is what I would like to run (assume I have variable v_sql with my sql query):
open my_cursor for v_sql;
Oracle doesnt like this though. I also tried
open my_cursor for
execute immediate v_sql;
Help please.
You need to declare it as a ref cursor and then open it for the your SQL statement. Please look at the example below. This, of course, is assuming you do not have any input bindings to your sql.
sql> ed
Wrote file afiedt.buf
1 declare
2 c1 sys_refcursor;
3 v_empno number;
4 v_ename varchar2(30);
5 begin
6 open c1 for 'select empno, ename from emp';
7 loop
8 fetch c1 into v_empno, v_ename;
9 dbms_output.put_line(v_empno || '--' || v_ename);
10 exit when c1%notfound;
11 end loop;
12 close c1;
13* end;
sql> /
7369--SMITH
7499--ALLEN
7521--WARD
7566--JONES
7654--MARTIN
7698--BLAKE
7782--CLARK
7788--SCOTT
7839--KING
7844--TURNER
7876--ADAMS
7900--JAMES
7902--FORD
7934--MILLER
7934--MILLER
Check this link...
http://download.oracle.com/docs/cd/B14117_01/appdev.101/b10807/11_dynam.htm#i13057
The first snippet you have will work fine, as long as v_sql is a VARCHAR and my_cursor is declared as a REF CURSOR. You can then FETCH from that just like you would with a static cursor.
But as OMG Ponies says, you have to be careful about where your SQL is coming from.
OMG Ponies is completely correct,
but here is just a different way to do the same thing
Var X Refcursor;
Begin
Open :X For
Select 1 Num, 'b' Co
From Dual
Union
Select 2 Num, 'c' Co
From Dual;
end;
/
print x;
Note when you do anything in Oracle like opening cursors or whatnot you will need to be within a BEGIN/END and you cannot simply do:
Var X Refcursor;
Open X For
Select 1 Num, 'b' Co
From Dual
Union
Select 2 Num, 'c' Co
From Dual;
This will not Work! You must enclose the OPEN cursor within a BEGIN/END block (be it an anonomous block or a procedure...)
Create or replace Procedure Ccc(X Out sys_Refcursor)
As
begin
Open X For
Select 1 Num, 'b' Co
From Dual
Union
Select 2 Num, 'c' Co
From Dual;
End Ccc;
/
Var X Refcursor;
Begin
Ccc(:X);
End;
/
print x;
note the :x in the begin/end in the anonomous blocks is to tell the sql engine you are utilizing a variable created outside the block. within packages/procs it is unnecessary.
i m using Oracle 9i.
I m fetching data from a cursor into an array :
FETCH contract_cur
BULK COLLECT INTO l_contract ;
But now i want to "convert" this l_contract into a CLOB variable l_clob
Is there an easy way to do that?
Or otherwise, how do i convertthe rows from a SELECT statement into one single CLOB Variable ?
thanks
EDIT : i forgot to mention its an array of %ROWTYPE, not just one column.
What an ugly thing to do.
Is it all character data, or do you have numeric and/or date/time values in there too ? If so what format do you want to use for those datatypes when you convert them to strings.
You also may need to think about field and record delimiters.
Have you considered XML ?
declare
v_clob clob;
v_xml xmltype;
begin
select xmlagg(XMLELEMENT("test",xmlforest(id,val)))
into v_xml
from test;
select v_xml.getclobval
into v_clob
from dual;
dbms_output.put_line(v_clob);
end;
/
you can loop through your array and build the CLOB as you go:
SQL> DECLARE
2 TYPE tab_vc IS TABLE OF VARCHAR2(4000);
3 l_contract tab_vc;
4 l_clob CLOB;
5 BEGIN
6 dbms_lob.createtemporary (l_clob, TRUE);
7 SELECT to_char(dbms_random.STRING('a', 1000)) BULK COLLECT
8 INTO l_contract
9 FROM dual
10 CONNECT BY LEVEL <= 100;
11 FOR i IN 1..l_contract.count LOOP
12 dbms_lob.writeappend(l_clob,
13 length(l_contract(i)),
14 l_contract(i));
15 END LOOP;
16 -- your code here
17 dbms_lob.freetemporary(l_clob);
18 END;
19 /
PL/SQL procedure successfully completed
If you don't use l_contract for anything else you can build the CLOB directly from the cursor loop without the array step, it will save memory and will probably be faster:
SQL> DECLARE
2 l_clob CLOB;
3 BEGIN
4 dbms_lob.createtemporary (l_clob, TRUE);
5 FOR cc IN ( SELECT to_char(dbms_random.STRING('a', 1000)) txt
6 FROM dual
7 CONNECT BY LEVEL <= 100) LOOP
8 dbms_lob.writeappend(l_clob,
9 length(cc.txt),
10 cc.txt);
11 END LOOP;
12 -- your code here
13 dbms_lob.freetemporary(l_clob);
14 END;
15 /
PL/SQL procedure successfully completed