returning value to cursor plsql - plsql

Hi I have a procedure which return a recordset using cursor in output what am trying to do is i use cursor to get the data and same have to return it to output cursor .I can do like below
PROCEDURE test(value_one IN someTabel.somecolumn%TYPE,
valu_two IN someTabel.somecolumn%TYPE,
Outputcursor OUT SYS_REFCURSOR) IS
mydeclaration goes here
output_value_one sometable.somecolumn%Type;
---
cursor test_select is
select statement
begin
for val in test_select loop
fetch test_select into output_value_one; -- I want my cursor outputcursor to be return instead of output_value_one
end loop;
end;

You send the deptno the cursor return the query where you can handle from frontend.
create or replace Procedure Transproc(p_deptno IN emp.deptno%TYPE,
Outputcursor Out Sys_Refcursor,
p_recordset Out Varchar)
Is
Vquery varchar2(200);
Begin
Vquery:='select * from emp where deptno='|| p_deptno ||'';
Open Outputcursor For Vquery;
OMessage:='Success';
Exception
When others then
OMessage:='Fail';
End;
OR try below one as per your requriement.
CREATE OR REPLACE PROCEDURE get_emp_rs (p_deptno IN emp.deptno%TYPE,
p_recordset OUT SYS_REFCURSOR) AS
BEGIN
OPEN p_recordset FOR
SELECT ename,
empno,
deptno
FROM emp
WHERE deptno = p_deptno
ORDER BY ename;
END GetEmpRS;
/
To test :-
SET SERVEROUTPUT ON SIZE 1000000
DECLARE
l_cursor SYS_REFCURSOR;
l_ename emp.ename%TYPE;
l_empno emp.empno%TYPE;
l_deptno emp.deptno%TYPE;
BEGIN
get_emp_rs (p_deptno => 30,
p_recordset => l_cursor);
LOOP
FETCH l_cursor
INTO l_ename, l_empno, l_deptno;
EXIT WHEN l_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(l_ename || ' | ' || l_empno || ' | ' || l_deptno);
END LOOP;
CLOSE l_cursor;
End;
/

Related

error in pl/sql package body

I am having this error:
Error(42,22): PLS-00103: Encountered the symbol ")" when expecting one of the following: current
I have written a package with few functions and procedures.
here is my package:
-- specification --
CREATE OR REPLACE PACKAGE SUPERHERO_PACKAGE AS
FUNCTION GET_FULL_SUPERHERONAME(V_SUPERHERONAME IN VARCHAR2)
RETURN VARCHAR2;
PROCEDURE GET_SUPERHEROS(V_CITY IN VARCHAR2);
PROCEDURE GET_ALL_VILLANS;
FUNCTION GET_MAX_XP
RETURN NUMBER;
FUNCTION GET_STRONGEST_SUPERHERO
RETURN VARCHAR2;
END SUPERHERO_PACKAGE;
-- body --
CREATE OR REPLACE PACKAGE BODY SUPERHERO_PACKAGE AS
FUNCTION GET_FULL_SUPERHERONAME(V_SUPERHERONAME IN VARCHAR2)
RETURN VARCHAR2 AS
BEGIN
SELECT FIRST_NAME, LAST_NAME
INTO V_FNAME, V_LNAME
FROM SUPERHERO
WHERE SUPERHERO_NAME = V_SUPERHERONAME;
RETURN (V_FNAME || " " || V_LNAME);
END;
PROCEDURE GET_SUPERHEROS(V_CITY IN VARCHAR2) IS
CURSOR JUSTICE_LEAGUE IS
SELECT SUPERHERO_NAME FROM SUPERHERO WHERE CITY = V_CITY;
LEAGUE_MEMBER JUSTICE_LEAGUE % ROWTYPE;
BEGIN
OPEN JUSTICE_LEAGUE;
LOOP
FETCH JUSTICE_LEAGUE INTO LEAGUE_MEMBER;
EXIT WHEN (JUSTICE_LEAGUE % NOTFOUND);
DBMS_OUTPUT.PUT_LINE(LEAGUE_MEMBER.NAME);
END LOOP;
CLOSE JUSTICE_LEAGUE;
END;
PROCEDURE GET_ALL_VILLANS IS
CURSOR DARK_FORCE IS
SELECT VILLAN FROM SUPERHERO;
FORCE_MEMBER DARK_FORCE % ROWTYPE;
BEGIN
OPEN DARK_FORCE;
LOOP
FETCH DARK_FORCE INTO FORCE_MEMBER;
EXIT WHEN (DARK_FORCE % NOTFOUND);
DBMS_OUTPUT.PUT_LINE(FORCE_MEMBER.VILLAN);
END LOOP;
CLOSE DARK_FORCE;
END;
FUNCTION GET_MAX_XP()
RETURN NUMBER AS
DECLARE
N_XP := 0;
BEGIN
SELECT MAX(XP) INTO N_XP FROM SUPERHERO;
RETURN N_XP;
END;
FUNCTION GET_STRONGEST_SUPERHERO()
RETURN VARCHAR2 AS
DECLARE
V_NAME := 'DNA';
V_FNAME := 'SWAYAM';
V_LNAME := 'RAINA';
BEGIN
SELECT SUPERHERO_NAME, FIRST_NAME, LAST_NAME
INTO V_NAME, V_FNAME, V_LNAME
FROM SUPERHERO
WHERE XP = GET_MAX_XP();
RETURN (V_FNAME || " " || V_LNAME || " AKA " || V_NAME);
END;
END SUPERHERO_PACKAGE;
You code is full of mistakes. Please check below the corrections.
CREATE OR REPLACE PACKAGE SUPERHERO_PACKAGE
AS
FUNCTION GET_FULL_SUPERHERONAME (V_SUPERHERONAME IN VARCHAR2) RETURN VARCHAR2;
PROCEDURE GET_SUPERHEROS (V_CITY IN VARCHAR2);
PROCEDURE GET_ALL_VILLANS;
FUNCTION GET_MAX_XP RETURN NUMBER;
FUNCTION GET_STRONGEST_SUPERHERO RETURN VARCHAR2;
END SUPERHERO_PACKAGE;
-- body --
CREATE OR REPLACE PACKAGE BODY SUPERHERO_PACKAGE
AS
FUNCTION GET_FULL_SUPERHERONAME (V_SUPERHERONAME IN VARCHAR2)
RETURN VARCHAR2 AS
V_FNAME varchar2(1000);
V_LNAME varchar2(1000);
BEGIN
SELECT FIRST_NAME, LAST_NAME
INTO V_FNAME, V_LNAME
FROM SUPERHERO
WHERE SUPERHERO_NAME = V_SUPERHERONAME;
RETURN(V_FNAME||'--'||V_LNAME);
END;
PROCEDURE GET_SUPERHEROS (V_CITY IN VARCHAR2)
IS
CURSOR JUSTICE_LEAGUE(vr_city VARCHAR2) --- parameterized Query
IS
SELECT SUPERHERO_NAME
FROM SUPERHERO
WHERE CITY = vr_city;
LEAGUE_MEMBER JUSTICE_LEAGUE%ROWTYPE;
BEGIN
OPEN JUSTICE_LEAGUE(V_CITY); --This is the way to call.
LOOP
FETCH JUSTICE_LEAGUE INTO LEAGUE_MEMBER;
EXIT WHEN JUSTICE_LEAGUE%NOTFOUND; -- No brackets needed
DBMS_OUTPUT.PUT_LINE(LEAGUE_MEMBER.SUPERHERO_NAME);
END LOOP;
CLOSE JUSTICE_LEAGUE;
END;
PROCEDURE GET_ALL_VILLANS
IS
CURSOR DARK_FORCE
IS
SELECT VILLAN
FROM SUPERHERO;
FORCE_MEMBER DARK_FORCE%ROWTYPE;
BEGIN
OPEN DARK_FORCE;
LOOP
FETCH DARK_FORCE INTO FORCE_MEMBER;
EXIT WHEN DARK_FORCE%NOTFOUND;
DBMS_OUTPUT.PUT_LINE (FORCE_MEMBER.VILLAN);
END LOOP;
CLOSE DARK_FORCE;
END;
FUNCTION GET_MAX_XP
RETURN NUMBER
AS
N_XP number:= 0; --Never use declare here
BEGIN
SELECT MAX (XP) INTO N_XP FROM SUPERHERO;
RETURN N_XP;
END;
FUNCTION GET_STRONGEST_SUPERHERO
RETURN VARCHAR2
AS
V_NAME varchar2(1000) := 'DNA'; --------Declaration Missing
V_FNAME varchar2(1000) := 'SWAYAM';
V_LNAME varchar2(1000) := 'RAINA';
BEGIN
SELECT SUPERHERO_NAME, FIRST_NAME, LAST_NAME
INTO V_NAME, V_FNAME, V_LNAME
FROM SUPERHERO
WHERE XP = (SELECT GET_MAX_XP() from dual); ----general practrice to call a function in where clause
RETURN (V_FNAME||' '||V_LNAME||'AKA'||V_NAME); --no double quotes
END;
END SUPERHERO_PACKAGE;

how to Pass table name to PL SQL cursor dynamically?

I have written one SQL Procedure where I have written one cursor and every time i have to pass table name to cursor query dynamically .
create or replace
PROCEDURE Add_DEN as
v_TableName VARCHAR2(4000) := 'BO_USER_DATA';
cursor c_DEN is select * from BO_USER_DATA; // Want to pass dynamically ,now hardcoded
r_DEN c_DEN%ROWTYPE;
fetch c_DEN into r_DEN;
v_Name := r_DEN."Name";
Can i write something like this
cursor c_DEN is "select * from " || v_TableName;
Any Help ?
here an example:
declare
TYPE curtype IS REF CURSOR;
l_cursor curtype;
l_param number;
l_key number;
l_value number;
l_sql varchar2(200);
begin
/* build your sql... */
l_sql := 'with data as (select 1 key, 100 value from dual union select 2, 200 from dual union select 3, 300 from dual union select 3, 301 from dual)' ||
' select key, value from data where key = :1';
l_param := 3;
open l_cursor for l_sql
using l_param;
loop
fetch l_cursor
into l_key, l_value;
exit when l_cursor%notfound;
dbms_output.put_line(l_key||' = '||l_value);
end loop;
close l_cursor;
end;
Result:
3 = 300
3 = 301
The basic answer is yes, you can and Given your example I would recommend you to use execute immediate to execute an arbitrary SQL string and bind the variables.
I would nevertheless reconsider if you really needed to dynamically set the table as this is not very often really needed.
Example:
DECLARE
sql_stmt VARCHAR2(200);
emp_id NUMBER(4) := 7566;
emp_rec emp%ROWTYPE;
BEGIN
sql_stmt := 'SELECT * FROM emp WHERE empno = :id';
EXECUTE IMMEDIATE sql_stmt INTO emp_rec USING emp_id;
END;

TOAD displaying cursor recordset returned by stored procedure

How I could print recorset result from the returning cursor, please.
Down below executes fine but I need to see result.
This is block in TOAD, calling package sp AMD_NEEDMSG:
DECLARE
RETURN_RECORDSET CTI_MATRIX.AMD.REF_CURSOR;
BEGIN
CTI_MATRIX.AMD.AMD_NEEDMSG ( '88888888885', RETURN_RECORDSET );
END;
This package spec:
CREATE OR REPLACE PACKAGE CTI_MATRIX.AMD AS
TYPE REF_CURSOR IS REF CURSOR;
PROCEDURE AMD_NEEDMSG (v_CRN IN VARCHAR2, return_recordset OUT REF_CURSOR);
END AMD;
This is package body:
CREATE OR REPLACE PACKAGE BODY CTI_MATRIX.AMD AS
PROCEDURE AMD_NEEDMSG (v_CRN IN VARCHAR2, return_recordset OUT REF_CURSOR) IS
return_flag INTEGER;
row_cnt INTEGER;
number_of_days INTEGER;
var_DATE DATE;
CURSOR ACCNTSEARCH (P_CRN IN VARCHAR2) IS
SELECT DISTINCT COUNT(*) , AMD.MSG_DATE
FROM TBL_AMD_NEEDMSG AMD
WHERE AMD.PHONE_NUMBER = P_CRN AND ROWNUM = 1;
BEGIN
OPEN ACCNTSEARCH(v_CRN);
FETCH ACCNTSEARCH INTO row_cnt, var_DATE;
CLOSE ACCNTSEARCH;
IF (row_cnt = 0)
THEN
INSERT INTO TBL_AMD_NEEDMSG (PHONE_NUMBER, MSG_DATE) VALUES (v_CRN , SYSDATE);
return_flag := 1;
ELSE
SELECT SYSDATE-var_DATE INTO number_of_days FROM dual;
IF (number_of_days>7)
THEN
UPDATE TBL_AMD_NEEDMSG SET MSG_DATE = SYSDATE WHERE PHONE_NUMBER = v_CRN;
return_flag := 1;
ELSE
return_flag := 0;
END IF;
END IF;
COMMIT;
OPEN return_recordset FOR
SELECT return_flag AS ReturnFLag FROM DUAL;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
END AMD_NEEDMSG;
END AMD;
/
Bottom line is to return to client a value of return_flag in the form of record set.
To return the return_flag, which is int=1 or 0 you need function that returns a single value, not recordset. Below are general recordset examples - hope this helps:
DECLARE
TYPE empcurtyp IS REF CURSOR;
emp_cv empcurtyp;
--
TYPE namelist IS TABLE OF scott.emp.ename%TYPE;
TYPE sallist IS TABLE OF scott.emp.sal%TYPE;
names namelist;
sals sallist;
BEGIN
OPEN emp_cv FOR
SELECT ename, sal FROM scott.emp
WHERE job = 'MANAGER' ORDER BY sal DESC;
--
FETCH emp_cv BULK COLLECT INTO names, sals;
CLOSE emp_cv;
-- loop through the names and sals collections
FOR i IN names.FIRST .. names.LAST LOOP
DBMS_OUTPUT.PUT_LINE
('Name = ' || names(i) || ', salary = ' || sals(i));
END LOOP;
END;
/
-- SYS_REFCURSOR example --
DECLARE
p_rc_type SYS_REFCURSOR;
emp_rec scott.emp%ROWTYPE;
--
PROCEDURE p_Emp_Info (p_cur_var OUT SYS_REFCURSOR)
IS
BEGIN
OPEN p_cur_var FOR
SELECT ename, job FROM scott.emp WHERE job = 'MANAGER';
LOOP
FETCH p_cur_var INTO emp_rec.ename, emp_rec.job;
EXIT WHEN p_cur_var%NOTFOUND;
dbms_output.put_line(emp_rec.ename ||' '|| emp_rec.job);
END LOOP;
CLOSE p_cur_var;
END p_Emp_Info;
--
BEGIN
p_Emp_Info(p_rc_type);
END;
/

Can I pass an explicit cursor to a function/procedure for use in FOR loop?

I have a procedure that performs some calculations on all records returned by a cursor. It looks a bit like this:
PROCEDURE do_calc(id table.id_column%TYPE)
IS
CURSOR c IS
SELECT col1, col2, col3
FROM table
WHERE ...;
BEGIN
FOR r IN c LOOP
-- do some complicated calculations using r.col1, r.col2, r.col3 etc.
END LOOP;
END;
Now I have the case where I need to perform the exact same calculation on a different set of records that come from a different table. However, these have the same "shape" as in the above in example.
Is it possible to write a procedure that looks like this:
PROCEDURE do_calc2(c some_cursor_type)
IS
BEGIN
FOR r IN c LOOP
-- do the calc, knowing we have r.col1, r.col2, r.col3, etc.
END LOOP;
END;
I know about SYS_REFCURSOR, but I was wondering if it was possible to use the much more convenient FOR ... LOOP syntax and implicit record type.
Create a package.
Declare your cursor as package variable.
Use %rowtype to set function parameter type.
create or replace package test is
cursor c is select 1 as one, 2 as two from dual;
procedure test1;
function test2(test_record c%ROWTYPE) return number;
end test;
create or replace package body test is
procedure test1 is
begin
for r in c loop
dbms_output.put_line(test2(r));
end loop;
end;
function test2(test_record c%ROWTYPE) return number is
l_summ number;
begin
l_summ := test_record.one + test_record.two;
return l_summ;
end;
end test;
I had a similar problem, where I had two cursors that needed to be processed the same way, so this is how I figured it out.
DECLARE
--Define our own rowType
TYPE employeeRowType IS RECORD (
f_name VARCHAR2(30),
l_name VARCHAR2(30));
--Define our ref cursor type
--If we didn't need our own rowType, we could have this: RETURN employees%ROWTYPE
TYPE empcurtyp IS REF CURSOR RETURN employeeRowType;
--Processes the cursors
PROCEDURE process_emp_cv (emp_cv IN empcurtyp) IS
person employeeRowType;
BEGIN
LOOP
FETCH emp_cv INTO person;
EXIT WHEN emp_cv%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('Name = ' || person.f_name ||
' ' || person.l_name);
END LOOP;
END;
--Defines the cursors
PROCEDURE mainProcedure IS
emp empcurtyp;
BEGIN
OPEN emp FOR SELECT first_name, last_name FROM employees WHERE salary > 50000;
process_emp_cv(emp);
CLOSE emp;
OPEN emp FOR SELECT first_name, last_name FROM kuren WHERE first_name LIKE 'J%';
process_emp_cv(emp);
CLOSE emp;
END;
BEGIN
mainProcedure;
END;
/
You can also use this if you want to bulk collect your cursors. You just need to change your helper procedure process_emp_cv; the rest can stay the same.
Using BULK COLLECT
--Processes the cursors
PROCEDURE process_emp_cv (emp_cv IN empcurtyp) IS
TYPE t_employeeRowTable IS TABLE OF employeeRowType;
employeeTable t_employeeRowTable;
BEGIN
LOOP
FETCH emp_cv BULK COLLECT INTO employeeTable LIMIT 50;
FOR indx IN 1 .. employeeTable.Count
LOOP
DBMS_OUTPUT.PUT_LINE('Name = ' || employeeTable(indx).f_name ||
' ' || employeeTable(indx).l_name);
END LOOP;
EXIT WHEN emp_cv%NOTFOUND;
END LOOP;
END;
Try this one, Usong ref cursor.
declare
type c is ref cursor;
c2 c;
type rec is record(
id number,
name varchar(20)
);
r rec;
procedure p1(c1 in out c,r1 in out rec)is begin
loop
fetch c1 into r1;
exit when c1%notfound;
dbms_output.put_line(r1.id || ' ' ||r1.name);
end loop;
end;
begin
open c2 for select id, name from student;
p1(c2,r);
end;
Yes you can use Cursor explicitly into procedure and function,for that cursor need to declare into package as variable

How to solve the Issue declaring a cursor in a Procedure/Package?

I'm new to Oracle and having issues declaring a cursor within my package. Can anyone tell me what i'm doing wrong?
Thanks
CREATE OR REPLACE PACKAGE CHECK_STOCK_LEVELS AS
PROCEDURE CHECK_PAYMTS_AGAINST_INVOICES;
FUNCTION CHECK_PROD_PRICE RETURN NUMBER;
END;
/
CREATE OR REPLACE PACKAGE BODY CHECK_STOCK_LEVELS AS
FUNCTION CHECK_PROD_PRICE (INP_PROD_NAME VARCHAR2)
RETURN NUMBER
IS
PROD_CNT PRODUCT.PROD_NAME%TYPE;
BEGIN
SELECT PROD_PRICE INTO PROD_CNT
FROM PRODUCT WHERE PROD_PRICE = INP_PROD_NAME;
RETURN (PROD_CNT);
END CHECK_PROD_PRICE;
/
SELECT CHECK_STOCK_LEVELS.CHECK_PROD_PRICE(3.5mm Jack) FROM DUAL;
PROCEDURE CHECK_PAYMTS_AGAINST_INVOICES
DECLARE CURSOR SEL_PAYMTS_AND_INVS
IS
SELECT P.INVOICE_ID, P.PAYMENT_AMOUNT, I.INVOICE_AMOUNT
FROM PAYMENT P
INNER JOIN INVOICE I ON P.INVOICE_ID = I.INVOICE_ID;
V_TEMP_RESULTS_ROW SEL_PAYMTS_AND_INVS%ROWTYPE;
PAYMT_INVOICE_MISMATCH EXCEPTION;
BEGIN
OPEN SEL_PAYMTS_AND_INVS;
FETCH SEL_PAYMTS_AND_INVS INTO V_TEMP_RESULTS_ROW;
WHILE SEL_PAYMTS_AND_INVS%FOUND LOOP
IF V_TEMP_RESULTS_ROW.PAYMENT_AMOUNT != V_TEMP_RESULTS_ROW.INVOICE_AMOUNT THEN
DBMS_OUTPUT.PUT_LINE('EMPLOYEE ID : ' || V_EMPLOYEE_ROW.EMPID || ' HAS A SALARY OF : ' || V_EMPLOYEE_ROW.SALARY);
RAISE PAYMT_INVOICE_MISMATCH;
END IF;
FETCH SEL_PAYMTS_AND_INVS INTO V_TEMP_RESULTS_ROW;
END LOOP;
CLOSE SEL_PAYMTS_AND_INVS;
EXCEPTION
WHEN PAYMT_INVOICE_MISMATCH THEN
DBMS_OUTPUT.PUT_LINE('PAYMENT AMOUNT DOES NOT MATCH INVOICE AMOUNT');
RAISE;
END;
END;
This:
SELECT CHECK_STOCK_LEVELS.CHECK_PROD_PRICE(3.5mm Jack) FROM DUAL;
should be:
SELECT CHECK_STOCK_LEVELS.CHECK_PROD_PRICE('3.5mm Jack') FROM DUAL;
And this:
PROCEDURE CHECK_PAYMTS_AGAINST_INVOICES
DECLARE CURSOR SEL_PAYMTS_AND_INVS
IS
SELECT P.INVOICE_ID, P.PAYMENT_AMOUNT, I.INVOICE_AMOUNT
FROM PAYMENT P
INNER JOIN INVOICE I ON P.INVOICE_ID = I.INVOICE_ID;
V_TEMP_RESULTS_ROW SEL_PAYMTS_AND_INVS%ROWTYPE;
PAYMT_INVOICE_MISMATCH EXCEPTION;
BEGIN
...
should be:
PROCEDURE CHECK_PAYMTS_AGAINST_INVOICES
IS -- not DECLARE
CURSOR SEL_PAYMTS_AND_INVS
IS
SELECT P.INVOICE_ID, P.PAYMENT_AMOUNT, I.INVOICE_AMOUNT
FROM PAYMENT P
INNER JOIN INVOICE I ON P.INVOICE_ID = I.INVOICE_ID;
V_TEMP_RESULTS_ROW SEL_PAYMTS_AND_INVS%ROWTYPE;
PAYMT_INVOICE_MISMATCH EXCEPTION;
BEGIN
...

Resources