ORACLE - can i pass cursor in a parameter and how to use it? - oracle

Here is one of oracle procedure. There is a cursor called r_ba.
DECLARE
r_ba SYS_REFCURSOR;
BEGIN
OPEN r_ba FOR
SELECT head.*,
line.jenis_pekerjaan,
line.deskripsi_pekerjaan,
line.akun,
line.rate_ppn,
line.dpp,
line.ppn,
line.total_realisasi,
line.major,
line.minor,
line.sla
FROM idm_ap_mtc_acl_header_tmp head, idm_ap_mtc_acl_lines_tmp line
WHERE head.no_ba = line.no_ba AND head.req_id = line.req_id AND head.req_id = n_req_id;
create_invoice_ap2 (
p_org_id => p_org_id,
p_user_id => p_user_id,
p_branch_code => v_branch_code,
r_ba => r_ba);
END;
and how call that cursor in this procedure ?
PROCEDURE create_invoice_ap2 (p_org_id IN NUMBER,
p_user_id IN NUMBER,
p_branch_code IN VARCHAR2,
r_ba IN SYS_REFCURSOR)
IS
r_tax_info rt_tax_info;
rt_ba SYS_REFCURSOR;
BEGIN
------------ setup ------------
r_tax_info := get_tax_code (
p_date => rt_ba.tgl_ba,
p_group_tax_name => rt_ba.tax_name,
p_ppn_rate => rt_ba.ppn_rate,
p_dc_code => rt_ba.dc_code);
END;
oracle give me error
[Error] PLS-00487 (707: 64): PLS-00487: Invalid reference to variable 'RT_BA'
Anyone could suggest me a way to accomplish this?
Thanks

If you're passing refcursor into a parameter named r_ba, then - I believe - you should use it, not declare another (rt_ba):
PROCEDURE create_invoice_ap2 (p_org_id IN NUMBER,
p_user_id IN NUMBER,
p_branch_code IN VARCHAR2,
r_ba IN SYS_REFCURSOR)
IS
r_tax_info rt_tax_info;
-- rt_ba SYS_REFCURSOR; --> you don't need it
BEGIN
------------ setup ------------
r_tax_info := get_tax_code (
p_date => r_ba.tgl_ba,
p_group_tax_name => r_ba.tax_name,
p_ppn_rate => r_ba.ppn_rate,
p_dc_code => r_ba.dc_code);
END; ----
^
|
r_ba, not rt_ba
Also, note that you should generally avoid select * because it can lead to ambiguity if there are columns with the same name as columns in other tables, so Oracle doesn't know which one you want to use.
The same goes for typos; for example, in anonymous PL/SQL block you're selecting line.rate_ppn, while procedure uses p_ppn_rate => r_ba.ppn_rate (rate_ppn vs. ppn_rate). Maybe it is OK because there's ppn_rate column in head table (which is in select head.*) but - once again - that's difficult to debug.
Furthermore, you can't use refcursor that way - you have to fetch from it. Have a look at example based on Scott's sample schema. Here's a procedure that accepts refcursor as a parameter and does something with it:
SQL> create or replace procedure p_test (r_ba in sys_refcursor)
2 is
3 l_dname varchar2(20);
4 begin
5 l_dname := r_ba.dname;
6 end;
7 /
Warning: Procedure created with compilation errors.
SQL> show err
Errors for PROCEDURE P_TEST:
LINE/COL ERROR
-------- -----------------------------------------------------------------
5/3 PL/SQL: Statement ignored
5/19 PLS-00487: Invalid reference to variable 'R_BA'
SQL>
See? The same error you got. Therefore, fetch:
SQL> create or replace procedure p_test (r_ba in sys_refcursor)
2 is
3 l_row dept%rowtype;
4 begin
5 loop
6 fetch r_ba into l_row;
7 exit when r_ba%notfound;
8 dbms_output.put_line(l_row.deptno ||', '|| l_row.dname ||', '|| l_row.loc);
9 end loop;
10 end;
11 /
Procedure created.
SQL> declare
2 r_ba sys_refcursor;
3 begin
4 open r_ba for select deptno, dname, loc from dept;
5 p_test (r_ba);
6 end;
7 /
10, ACCOUNTING, NEW YORK
20, RESEARCH, DALLAS
30, SALES, CHICAGO
40, OPERATIONS, BOSTON
PL/SQL procedure successfully completed.
SQL>
Now it is OK.
I don't know what you're doing with r_tax_info, how many rows refcursor contains (whether you need to use a loop or not), but - that's the general idea. Fetch first, use it next.

Related

ORA-00900: invalid SQL statement- when run a package in oracle 12c

I am using Oracle 12c database and trying to run a package using SQL commands.
CREATE OR REPLACE PACKAGE "PK_CP_OTM" as
FUNCTION F_CP_OPTIMIZATION (
v_current_day IN VARCHAR2,
v_branch_code IN VARCHAR2)
RETURN VARCHAR2;
END PK_CP_OTM;
When I try to execute it using:
DECLARE
BEGIN
EXECUTE IMMEDIATE PK_CP_OTM.F_CP_OPTIMIZATION('20190409','BRNCD001');
END;
It shows:
ORA-00900: invalid SQL statement
ORA-06512: at line 3
00900. 00000 - "invalid SQL statement"
Thanks for your help.
As #Littlefoot said, you don't need dynamic SQL here, you can make a static call; but as you are calling a function you do need somewhere to put the result of the call:
declare
l_result varchar2(30); -- make it a suitable size
begin
l_result := pk_cp_otm.f_cp_optimization('20190409','BRNCD001');
end;
/
In SQL*Plus, SQL Developer and SQLcl you can use the execute client command (which might have caused some confusion) and a bind variable for the result:
var result varchar2(30);
exec :result := pk_cp_otm.f_cp_optimization('20190409','BRNCD001');
print result
There's nothing dynamic here, so - why would you use dynamic SQL at all?
Anyway: if you insist, then you'll have to select the function into something (e.g. a local variable). Here's an example
First, the package:
SQL> set serveroutput on
SQL>
SQL> create or replace package pk_cp_otm
2 as
3 function f_cp_optimization (v_current_day in varchar2,
4 v_branch_code in varchar2)
5 return varchar2;
6 end pk_cp_otm;
7 /
Package created.
SQL> create or replace package body pk_cp_otm
2 as
3 function f_cp_optimization (v_current_day in varchar2,
4 v_branch_code in varchar2)
5 return varchar2
6 is
7 begin
8 return 'Littlefoot';
9 end;
10 end pk_cp_otm;
11 /
Package body created.
How to call the function?
SQL> declare
2 l_result varchar2 (20);
3 begin
4 execute immediate
5 'select pk_cp_otm.f_cp_optimization (''1'', ''2'') from dual'
6 into l_result;
7
8 dbms_output.put_line ('result = ' || l_result);
9 end;
10 /
result = Littlefoot
PL/SQL procedure successfully completed.
SQL>

plsql procedures while executing an error invalid identifier 00904

Error message
CREATE TABLE DEPARTMENT(DID INT,DNAME VARCHAR2(20),DLOC VARCHAR2(20));
INSERT INTO DEPARTMENT VALUES(101,'SRINATH','HINDUPUR');
INSERT INTO DEPARTMENT VALUES(102,'SAINATH','ANANTAPUR');
create or replace PROCEDURE ADD_DEPARTMENT
(P_DID IN DEPARTMENT.DID%TYPE,
P_DNAME IN DEPARTMENT.DNAME%TYPE,
P_DLOC IN DEPARTMENT.DLOC%TYPE,
P_ERROR_MSG OUT VARCHAR2)
IS
BEGIN
INSERT INTO DEPARTMENT(DID,DNAME,DLOC)VALUES(P_DID,P_DNAME,P_DLOC);
COMMIT;
EXCEPTION
WHEN OTHERS THEN
P_ERROR_MSG:=SQLERRM;
END ADD_DEPARTMENT;
iam writing a simple procedure try to excute but it shows object_id:invalid identifier how i can solve
complete procedure execution image
One of your column names may be wrong in the parameter list/insert. Try just using varchar2 for all of them and see if that helps
create or replace PROCEDURE ADD_DEPT2
(P_DEPTNO IN VARCHAR2,
P_DNAME IN VARCHAR2,
P_LOC IN VARCHAR2,
P_ERROR_MSG OUT VARCHAR2)
IS
BEGIN
INSERT INTO DEPT1(DEPTNO,DNAME,LOC)VALUES(P_DEPTNO,P_DNAME,P_LOC);
COMMIT;
EXCEPTION
WHEN OTHERS THEN
P_ERROR_MSG :=SQLERRM;
END ADD_DEPT2;
"it will come same error can be displayed"
No, no it won't. Let's prove it by running the code you posted.
Here is your table:
SQL> CREATE TABLE DEPARTMENT(DID INT,DNAME VARCHAR2(20),DLOC VARCHAR2(20));
Table created.
SQL> INSERT INTO DEPARTMENT VALUES(101,'SRINATH','HINDUPUR');
1 row created.
SQL> INSERT INTO DEPARTMENT VALUES(102,'SAINATH','ANANTAPUR');
1 row created.
SQL>
Here is your procedure:
SQL> create or replace PROCEDURE ADD_DEPARTMENT
2 (P_DID IN DEPARTMENT.DID%TYPE,
3 P_DNAME IN DEPARTMENT.DNAME%TYPE,
4 P_DLOC IN DEPARTMENT.DLOC%TYPE,
5 P_ERROR_MSG OUT VARCHAR2)
6 IS
7 BEGIN
8 INSERT INTO DEPARTMENT(DID,DNAME,DLOC)VALUES(P_DID,P_DNAME,P_DLOC);
9 COMMIT;
10 EXCEPTION
11 WHEN OTHERS THEN
12 P_ERROR_MSG:=SQLERRM;
13 END ADD_DEPARTMENT;
14 /
Procedure created.
SQL>
And lo! not only does it compile but it runs without error too.
SQL> set serveroutput on
SQL> declare
2 v varchar2(128);
3 begin
4 add_department(666, 'Area 51', 'Roswell', v);
5 end;
6 /
PL/SQL procedure successfully completed.
SQL> select * from department;
DID DNAME DLOC
---------- -------------------- --------------------
101 SRINATH HINDUPUR
102 SAINATH ANANTAPUR
666 Area 51 Roswell
SQL>
So once again I ask, what is the problem?
"PLS-00905: object SCOTT.ADD_DEPARTMENT is invalid"
In SQL*Plus:
Connect as SCOTT
alter procedure add_department compile;
show errors
Or apply the equivalent sequence for whatever IDE you use to write your code.

Using cursor with where in condition

I am passing arguments `EBN,BGE' into a procedure , then I am passing this argument to a cursor.
create or replace procedure TEXT_MD (AS_IDS VARCHAR2)
is
CURSOR C_A (AS_ID VARCHAR2) IS
SELECT
name
FROM S_US
WHERE US_ID IN (AS_ID);
BEGIN
FOR A IN C_A (AS_IDS) LOOP
DBMS_OUTPUT.PUT_LINE('I got here: '||AS_IDS);
end loop;
END;
But while debuging the count of the cursor is still null
So my question , why the cursor not returning values with in condition
You are passing a string parameter, so it will be used as a string, not as a list of strings; so, your cursor will be something like
SELECT name
FROM S_US
WHERE US_ID IN ('EBN,BGE')
This will, of course, not do what you need.
You may need to change your procedure and the way to pass parameters; if you want to keep a string parameter , one way could be the following:
setup:
SQL> CREATE TABLE S_US
2 (
3 US_ID,
4 NAME
5 ) AS
6 SELECT 'EBN', 'EBN name' FROM DUAL
7 UNION ALL
8 SELECT 'BGE', 'BGE name' FROM DUAL;
Table created.
procedure:
SQL> CREATE OR REPLACE PROCEDURE TEXT_MD_2(AS_IDS VARCHAR2) IS
2 vSQL varchar2(1000);
3 c sys_refcursor;
4 vName varchar2(16);
5 BEGIN
6 vSQL := 'SELECT name
7 FROM S_US
8 WHERE US_ID IN (' || AS_IDS || ')';
9 open c for vSQL;
10 loop
11 fetch c into vName;
12 if c%NOTFOUND then
13 exit;
14 end if;
15 DBMS_OUTPUT.PUT_LINE(vName);
16 END LOOP;
17 END;
18 /
Procedure created.
You need to call it with a string already formatted to be a parameter list for IN:
SQL> EXEC TEXT_MD_2('''EBN'',''BGE''');
EBN name
BGE name
PL/SQL procedure successfully completed.
This is only an example of a possible way, and not the way I would do this.
Among the reasons to avoud this kind of approach, consider what Justin Cave says:
"that would be a security risk due to SQL injection and would have a potentially significant performance penalty due to constant hard parsing".
I believe you should better check how to pass a list of values to your procedure, rather then using a string to represent a list of strings.
Here is a possible way to do the same thing with a collection:
SQL> CREATE OR REPLACE TYPE tabVarchar2 AS TABLE OF VARCHAR2(16)
2 /
Type created.
SQL>
SQL> CREATE OR REPLACE PROCEDURE TEXT_MD_3(AS_IDS tabVarchar2) IS
2 vSQL VARCHAR2(1000);
3 c SYS_REFCURSOR;
4 vName VARCHAR2(16);
5 BEGIN
6 FOR i IN (SELECT name
7 FROM S_US INNER JOIN TABLE(AS_IDS) tab ON (tab.COLUMN_VALUE = US_ID))
8 LOOP
9 DBMS_OUTPUT.PUT_LINE(i.name);
10 END LOOP;
11 END;
12 /
Procedure created.
SQL>
SQL> DECLARE
2 vList tabVarchar2 := NEW tabVarchar2();
3 BEGIN
4 vList.EXTEND(2);
5 vList(1) := 'BGE';
6 vList(2) := 'EBN';
7 TEXT_MD_3(vList);
8 END;
9 /
BGE name
EBN name
PL/SQL procedure successfully completed.
SQL>
Again, you can define collections in different ways, within a stored procedure or not, indexed or not, and so on; this is only one of the possible ways, not necessarily the best, depending on your environment, needs.

Oracle 11g View resultset of table from Stored procedure in Toad

I am a novice to Oracle 11g and would like to view the resultset of a table output from a stored procedure. I have created the procedure and executed it. I just want to view the output in the form of a grid like in SQL Server. Please help me out.
This is the declaration of my procedure:
Spec:
TYPE ret_cursor IS REF CURSOR;
procedure get_data(
p_start_dt in varchar2,
p_end_dt in varchar2,
p_results out ret_cursor,
p_err_no out number,
p_err_msg out varchar2
);
Body:
PROCEDURE get_data(
p_start_dt IN VARCHAR2,
p_end_dt IN VARCHAR2,
p_results OUT ret_cursor,
p_err_no OUT NUMBER,
p_err_msg OUT VARCHAR2
)
IF you are using TOAD ,then its very easy to see output of refcursor .
First copy below code in Toad Editor
DECLARE
v_err_no number;
v_err_msg VARCHAR2(200);
BEGIN
get_data(
p_start_dt => SYSDATE, --depend on you
p_end_dt => SYSDATE+10, --depend on you
p_results => :ret_cursor,
p_err_no => v_err_no,
p_err_msg => v_err_msg
);
--print error message
END;
Now goto Editor-->Execute Statement f9 ,and click
Popup appear ,and asking you for ret_cursor type,select type as cursor ,do as shown below in the screenshot
Click OK ,and then you can see result in the datagrid .
If you want simply look at the result you can use SQL*Plus and it's REFCURSOR bind variable and PRINT command:
SQL> create or replace procedure p
2 (
3 x out sys_refcursor
4 )
5 is
6 begin
7 open x for select 1 a, 'a' b from dual;
8 end;
9 /
Procedure created.
SQL> var rc refcursor
SQL> exec p(:rc)
PL/SQL procedure completed.
SQL> print rc
A B
---------- -
1 a

Get the name of the calling procedure or function in Oracle PL/SQL

Does anyone know whether it's possible for a PL/SQL procedure (an error-logging one in this case) to get the name of the function/procedure which called it?
Obviously I could pass the name in as a parameter, but it'd be nice to make a system call or something to get the info - it could just return null or something if it wasn't called from a procedure/function.
If there's no method for this that's fine - just curious if it's possible (searches yield nothing).
There is a package called OWA_UTIL (which is not installed by default in older versions of the database). This has a method WHO_CALLED_ME() which returns the OWNER, OBJECT_NAME, LINE_NO and CALLER_TYPE. Note that if the caller is a packaged procedure it will return the PACKAGE name not the procedure name. In this case there is no way of getting the procedure name; this is because the procedure name can be overloaded, so it's not necessarily very useful.
Find out more.
Since 10gR2 there is also the $$PLSQL_UNIT special function; this will also return the OBJECT NAME (i.e. package not packaged procedure).
I found this forum: http://www.orafaq.com/forum/t/60583/0/. It may be what you are looking.
Basically, you can use the Oracle supplied dbms_utility.format_call_stack:
scott#ORA92> CREATE TABLE error_tab
2 (who_am_i VARCHAR2(61),
3 who_called_me VARCHAR2(61),
4 call_stack CLOB)
5 /
Table created.
scott#ORA92>
scott#ORA92> CREATE OR REPLACE PROCEDURE d
2 AS
3 v_num NUMBER;
4 v_owner VARCHAR2(30);
5 v_name VARCHAR2(30);
6 v_line NUMBER;
7 v_caller_t VARCHAR2(100);
8 BEGIN
9 select to_number('a') into v_num from dual; -- cause error for testing
10 EXCEPTION
11 WHEN OTHERS THEN
12 who_called_me (v_owner, v_name, v_line, v_caller_t);
13 INSERT INTO error_tab
14 VALUES (who_am_i,
15 v_owner || '.' || v_name,
16 dbms_utility.format_call_stack);
17 END d;
18 /
Procedure created.
scott#ORA92> SHOW ERRORS
No errors.
scott#ORA92> CREATE OR REPLACE PROCEDURE c
2 AS
3 BEGIN
4 d;
5 END c;
6 /
Procedure created.
scott#ORA92> CREATE OR REPLACE PROCEDURE b
2 AS
3 BEGIN
4 c;
5 END b;
6 /
Procedure created.
scott#ORA92> CREATE OR REPLACE PROCEDURE a
2 AS
3 BEGIN
4 b;
5 END a;
6 /
Procedure created.
scott#ORA92> execute a
PL/SQL procedure successfully completed.
scott#ORA92> COLUMN who_am_i FORMAT A13
scott#ORA92> COLUMN who_called_me FORMAT A13
scott#ORA92> COLUMN call_stack FORMAT A45
scott#ORA92> SELECT * FROM error_tab
2 /
WHO_AM_I WHO_CALLED_ME CALL_STACK
------------- ------------- ---------------------------------------------
SCOTT.D SCOTT.C ----- PL/SQL Call Stack -----
object line object
handle number name
6623F488 1 anonymous block
66292138 13 procedure SCOTT.D
66299430 4 procedure SCOTT.C
6623D2F8 4 procedure SCOTT.B
6624F994 4 procedure SCOTT.A
66299984 1 anonymous block
scott#ORA92>
Basically, all you need to do is to define vars and pass them in a call to a utility method to fill them up with values:
create or replace procedure some_test_proc (p_some_int int)
is
owner_name VARCHAR2 (100);
caller_name VARCHAR2 (100);
line_number NUMBER;
caller_type VARCHAR2 (100);
begin
....
OWA_UTIL.WHO_CALLED_ME (owner_name,caller_name,line_number,caller_type);
-- now you can insert those values along with systimestamp into a log file
....
end;

Resources