oracle out ref cursor to a loop - oracle

How to pass the 'values' of the output cursor o_cur to a further loop?
CREATE OR REPLACE PROCEDURE dyn_cursor (o_cur OUT SYS_REFCURSOR)
IS
script VARCHAR2 (4000);
BEGIN
script := 'select sysdate-1 notnow, sysdate today from dual union all select sysdate+1 notnow, sysdate today from dual';
OPEN o_cur FOR script;
-- the question is related to this block:
for i in o_cur
loop
DBMS_OUTPUT.PUT_LINE(i.notnow);
end loop;
-----------------------
END;

FETCH is usually handled outside the procedure when the refcursor is an OUT variable
CREATE OR REPLACE PROCEDURE dyn_cursor (o_cur OUT SYS_REFCURSOR)
IS
script VARCHAR2 (4000);
BEGIN
script := 'select sysdate-1 notnow, sysdate today from dual union all select sysdate+1 notnow, sysdate today from dual';
OPEN o_cur FOR script;
END;
/
SET SERVEROUTPUT ON
DECLARE
v_cur SYS_REFCURSOR;
v_notnow DATE;
v_today DATE;
BEGIN
dyn_cursor(v_cur);
LOOP
FETCH v_cur INTO
v_notnow,
v_today;
EXIT WHEN v_cur%notfound;
dbms_output.put_line(v_notnow);
END LOOP;
END;
/
02-10-18
04-10-18
PL/SQL procedure successfully completed.

This seems a strange construct. I would create a view you can reuse at different places.
CREATE OR REPLACE VIEW VW_Times AS
SELECT sysdate-1 notnow, sysdate today FROM dual
UNION ALL
SELECT sysdate+1 notnow, sysdate today FROM dual;
and
CREATE OR REPLACE PROCEDURE OutputTime ()
IS
CURSOR o_cur IS
SELECT * FROM VW_Times;
BEGIN
FOR i IN o_cur
LOOP
DBMS_OUTPUT.PUT_LINE(i.notnow);
END LOOP;
END;

Tanks to post of Kaushik Nayak, I found the acceptable solution:
CREATE OR REPLACE PROCEDURE dyn_cursor (o_cur OUT SYS_REFCURSOR)
IS
script VARCHAR2 (4000);
type array is table of VARCHAR2(20) index by binary_integer;
l_datapoint1 array;
l_datapoint2 array;
BEGIN
script := 'select sysdate-1 notnow, sysdate today from dual union all select sysdate+1 notnow, sysdate today from dual';
OPEN o_cur FOR script;
LOOP
FETCH o_cur bulk collect into l_datapoint1, l_datapoint2;
for i in 1 .. l_datapoint1.count
loop
DBMS_OUTPUT.PUT_LINE( l_datapoint1(i) || ', ' || l_datapoint2(i) );
end loop;
exit when o_cur%notfound;
end loop;
close o_cur;
END;

Related

Passing multiple input strings to Oracle query [duplicate]

This question already has answers here:
SELECT from table with Varying IN list in WHERE clause
(2 answers)
Closed 5 years ago.
I am passing an input value as 'MI,NOKIA,APPLE' to a procedure. This input value has to be passed to the query in where condition.
For example:
create or replace procedure abc123(p_name varchar2)
is
v_val number;
begin
dbms_output.put_line ('p_name: '||p_name );
Select 1
Into v_val
from MYTABLE
where Model in p_name;
dbms_output.put_line ('v_val: '||v_val );
end;
This is not working. How do I pass the multiple input values as single parameter?
Use paranthesis after IN operator :
Select 1 Into v_val from MYTABLE where Model in (p_name);
try below code,
create or replace procedure proc123 (p_param VARCHAR2)
IS
TYPE cur_typ IS REF CURSOR;
c cur_typ;
v_query VARCHAR2(200) := 'SELECT * '||
'FROM (SELECT ''Model1'' model FROM dual '||
'union all '||
'SELECT ''Model2'' FROM dual '||
'union all '||
'SELECT ''Model3'' FROM dual)';
v_model VARCHAR2(20);
BEGIN
v_query := v_query||' WHERE INSTR('''||p_param||''',model) > 0';
dbms_output.put_line(v_query);
OPEN c FOR v_query;
LOOP
FETCH c INTO v_model;
EXIT WHEN c%NOTFOUND;
dbms_output.put_line(v_model);
END LOOP;
CLOSE c;
END;
/
--set your dbms_output on
begin
proc123('Model1, Model2');
end;
/
if you want to pass the parameter in a query, then you can use the INSTR function
Select 1
from MYTABLE
where INSTR(p_name, model) > 0;

How to fetch a ref_cursor into Oracle's WITH CLAUSE

Is it possible to use a ref_cursor with ORACLE WITH CLAUSE. For example, I have the following scenario. First I have a procedure which returns a ref_cursor
PROCEDURE p_return_cursor(p_id IN NUMBER, io_cursor OUT t_cursor)
AS
BEGIN
OPEN io_cursor FOR
SELECT col1, col2
FROM Table1 t
WHERE t.id = p_id;
END;
Second, I have another procedure on which I make a call to p_return_cursor:
PROCEDURE p_test(p_cid IN NUMBER)
AS
l_cursor t_cursor;
l_rec Table1%ROWTYPE;
BEGIN
p_return_cursor(p_id => p_cid, io_cursor => l_cursor);
-- CODE GOES HERE
...
Now, my question is, can I make a temp table using the Oracle's WITH CLAUSE using the cursor; something like:
...
WITH data AS (
LOOP
FETCH l_cursor INTO l_rec;
EXIT WHEN l_cursor%NOTFOUND;
SELECT l_rec.col1, l_rec.col2 FROM DUAL;
END LOOP;
CLOSE l_cursor;
)
You cannot do it directly. You can, however, BULK COLLECT your cursor into a PL/SQL table variable and use that in a WITH clause.
Be careful of memory usage if the cursor contains many rows.
Full example:
CREATE TABLE table1 ( col1 NUMBER, col2 NUMBER );
INSERT INTO table1 ( col1, col2 ) SELECT rownum, 100+rownum FROM DUAL CONNECT BY ROWNUM <= 15;
COMMIT;
CREATE OR REPLACE PACKAGE se_example AS
TYPE t_cursor IS REF CURSOR
RETURN table1%ROWTYPE;
TYPE l_rec_tab IS TABLE OF table1%ROWTYPE;
PROCEDURE p_test (p_cid IN NUMBER);
END se_example;
CREATE OR REPLACE PACKAGE BODY se_example AS
-- private
PROCEDURE p_return_cursor (p_id IN NUMBER, io_cursor OUT t_cursor) AS
BEGIN
OPEN io_cursor FOR
SELECT col1,
col2
FROM table1 t;
--WHERE t.id = p_id; -- I didn't put "id" column in my sample table, sorry...
END p_return_cursor;
PROCEDURE p_test (p_cid IN NUMBER) IS
l_cursor t_cursor;
l_tab l_rec_tab;
l_dummy NUMBER;
BEGIN
p_return_cursor (p_id => p_cid, io_cursor => l_cursor);
FETCH l_cursor BULK COLLECT INTO l_tab;
-- *** instead of this
-- WITH data AS (
-- LOOP
-- FETCH l_cursor INTO l_rec;
-- EXIT WHEN l_cursor%NOTFOUND;
-- SELECT l_rec.col1, l_rec.col2 FROM DUAL;
-- END LOOP;
-- CLOSE l_cursor;
-- )
-- '
--
-- *** do this
WITH data AS
( SELECT col1, col2 FROM TABLE(l_tab) )
SELECT sum(col1 * col2) INTO l_dummy
FROM data;
dbms_output.put_line('result is ' || l_dummy);
END p_test;
END se_example;
begin
se_example.p_test(100);
end;

Can I use with clause while opening a CURSOR

Can I use WITH clause while using cursor
OPEN CURSOR_NAME FOR
WITH view1 as (Select v_name from tablename),
view2 as (Select p_name from tablename2)
Select * from view1, view2;
Yes it is possible to use with clause in cursor. Check the below example.
DECLARE
l_cur sys_refcursor;
l_val VARCHAR2 (1000);
BEGIN
DBMS_OUTPUT.ENABLE;
OPEN l_cur FOR
WITH tab AS
(SELECT 'hello'
FROM DUAL)
SELECT *
FROM tab;
FETCH l_cur
INTO l_val;
CLOSE l_cur;
DBMS_OUTPUT.put_line (l_val);
END;
Output: hello

Comma separated values to IN function in oracle

I am trying to execute below query, but not getting any result.
Could some one tell what wrong I am doing?.
DECLARE
object_types VARCHAR2(200);
v_object_types VARCHAR2(200);
l_count number;
BEGIN
object_types :='TABLE,VIEW';
select ''''||regexp_replace(object_types, '( )*(,)( )*',''',''')||''''
into v_object_types from dual;
dbms_output.put_line(to_char(v_object_types));
SELECT count(*) into l_count
FROM all_objects o where o.object_type IN ('||v_object_types||');
dbms_output.put_line(l_count);
END;
WHERE variable IN (1,2,3)
is different to what you are sending now
WHERE variable IN ('1,2,3') or
WHERE variable IN ('||v_object_types||')
You are trying to build the SQL dynamically but instead you are using a single string literal '||v_object_types||' in the IN clause.
You can do it using a collection:
Oracle Setup:
CREATE TYPE stringlist IS TABLE OF VARCHAR2(200);
/
PL/SQL:
DECLARE
object_types VARCHAR2(200) := 'TABLE,VIEW';
v_object_types stringlist;
BEGIN
SELECT TRIM( BOTH FROM REGEXP_SUBSTR( object_types, '[^,]+', 1, LEVEL ) )
BULK COLLECT INTO v_object_types
FROM DUAL
CONNECT BY LEVEL <= REGEXP_COUNT( object_types, '[^,]+' );
FOR i IN 1 .. v_object_types.COUNT LOOP
dbms_output.put_line( v_object_types(i) );
END LOOP;
SELECT count(*)
INTO l_count
FROM all_objects
WHERE object_type MEMBER OF v_object_types;
dbms_output.put_line(l_count);
END;
/
or using dynamic sql:
DECLARE
object_types VARCHAR2(200) := 'TABLE,VIEW';
v_sql VARCHAR2(200);
l_count INTEGER;
BEGIN
v_sql := 'SELECT count(*) FROM all_objects WHERE object_type IN ('
|| REGEXP_REPLACE( object_types, ' *(.+?) *(,|$)', '''\1''\2' )
|| ')';
EXECUTE IMMEDIATE v_sql INTO l_count;
dbms_output.put_line(l_count);
END;
/

Stored procedure for counting the row count of all the tables in database of a specific owner [duplicate]

This question already has answers here:
Get counts of all tables in a schema
(6 answers)
Closed 8 years ago.
I am creating a stored procedure in oracle to find the row count of all the tables. I have to run these procedure daily to find the daily data that is being loaded after ETL. I have created the below procedure.
create or replace Procedure Proc_RSE_TABLE_ROW_Count AS
TYPE c_table_list IS REF CURSOR ;
C_table_name c_table_list;
RSE_ROW_COUNT NUMBER;
SQL_11g VARCHAR2(500);
SQL_CURSOR VARCHAR2(500);
V_TABLE_NAME VARCHAR2(30);
BEGIN
SQL_CURSOR := 'SELECT
TRIM(table_name) table_name
FROM RSE_TABLE_COUNT ';
OPEN C_table_name FOR SQL_CURSOR;
LOOP
FETCH C_table_name INTO V_TABLE_NAME;
EXIT WHEN C_table_name%NOTFOUND;
SQL_11g := 'SELECT COUNT(1) FROM '||V_TABLE_NAME;
EXECUTE IMMEDIATE SQL_11g INTO RSE_ROW_COUNT;
INSERT into RSE_TABLE_COUNT (TABLE_NAME, ROW_COUNT, DATE_LAST_UPDATED)
values ('vtable_name', rse_row_count, sysdate)
/*UPDATE RSE_TABLE_COUNT SET ROW_COUNT=RSE_ROW_COUNT,DATE_LAST_UPDATED=sysdate
WHERE table_name=V_TABLE_NAME;
commit; */
END LOOP;
CLOSE C_table_name;
END;
but instead of which i am currently using i want to insert the daily data. With update the history is getting over ridden. And with insert i am getting error. I want to insert table_name, row_count, and sysdate in the table when i run the procedure without affecting previous data. My i am new to oracle syntax so please help..
See the following code snippet, quite similar to what you have and it insert rows correctly.
CREATE TABLE RSE_TABLE_COUNT
(
TABLE_NAME VARCHAR2(500 BYTE),
ROW_COUNT NUMBER,
DATE_LAST_UPDATED DATE
);
CREATE OR REPLACE PROCEDURE Proc_RSE_TABLE_ROW_Count
AS
TYPE c_table_list IS REF CURSOR;
C_table_name c_table_list;
RSE_ROW_COUNT NUMBER;
SQL_11g VARCHAR2 (500);
SQL_CURSOR VARCHAR2 (500);
V_TABLE_NAME VARCHAR2 (30);
BEGIN
SQL_CURSOR := 'SELECT
object_name
FROM user_objects
WHERE object_type=''TABLE''';
OPEN C_table_name FOR SQL_CURSOR;
LOOP
FETCH C_table_name INTO V_TABLE_NAME;
EXIT WHEN C_table_name%NOTFOUND;
SQL_11g := 'SELECT COUNT(1) FROM ' || V_TABLE_NAME;
EXECUTE IMMEDIATE SQL_11g INTO RSE_ROW_COUNT;
INSERT INTO RSE_TABLE_COUNT (TABLE_NAME, ROW_COUNT, DATE_LAST_UPDATED)
VALUES (V_TABLE_NAME, rse_row_count, SYSDATE);
END LOOP;
CLOSE C_table_name;
END;
Why don't you analyze the schema (estimate_percent=100) and select num_rows from user_tables? Probaly allready there is a gather_schema_stats in your ETL. After that:
insert into rse_table_count
select table_name,num_rows,sysdate
from user_tables;

Resources