Oracle PL/SQL Developer: Return %RowType from Package Procedure - oracle

i'm kind of new to Oracle Pl\SQL. I was just trying to create a simple Package with a procedure that returns a set of object id's; the code is as follows:
--Package Spec
CREATE OR REPLACE PACKAGE TEST IS
--GET OBJECT ID'S FROM CONTROL TABLE
PROCEDURE get_object_id_control(p_obj_id OUT abc_table%ROWTYPE);
END;
--Package Body
PROCEDURE get_object_id_control(p_obj_id OUT abc_table%ROWTYPE) AS
BEGIN
SELECT object_id
INTO p_obj_id
FROM abc_table
WHERE fec_proc IS NULL;
END;
I get Error: PL/SQL: ORA-00913: too many values. Is this the correct way for returning multiple values of same data type, or is there a better approach. Thanks in advance.

You can create a custom table type and set the out parameter of the procedure to that type.
CREATE TABLE ABC_TABLE(ID varchar2(100));
create or replace type abc_tab is table of varchar2(100);
/
CREATE OR REPLACE PACKAGE TEST IS
PROCEDURE get_object_id_control(p_obj_id OUT abc_tab);
END;
/
CREATE OR REPLACE PACKAGE BODY TEST IS
PROCEDURE get_object_id_control(p_obj_id OUT abc_tab) AS
BEGIN
SELECT id
bulk collect INTO p_obj_id
FROM abc_table;
END;
END;
/
Then you can call it like so:
declare
v abc_tab;
begin
TEST.get_object_id_control(p_obj_id => v);
for i in v.first..v.last loop
dbms_output.put_line(v(i));
end loop;
end;
/

Similar to GurV's answer (since he beat me by like 30 seconds...), you can use a PL/SQL object type as well. You do not need the CREATE TYPE statement if you don't need to reference the type in SQL.
--Package Spec
CREATE OR REPLACE PACKAGE TEST AS
TYPE id_table_type IS TABLE OF NUMBER;
--GET OBJECT ID'S FROM CONTROL TABLE
PROCEDURE get_object_id_control(p_obj_id_list OUT id_table_type);
END;
--Package Body
CREATE OR REPLACE PACKAGE BODY TEST AS
PROCEDURE get_object_id_control(p_obj_id_list OUT id_table_type) AS
BEGIN
SELECT object_id
BULK COLLECT INTO p_obj_id_list
FROM abc_table
WHERE fec_proc IS NULL;
END;
END;
To use it:
DECLARE
l_id_list test.id_table_type;
BEGIN
test.get_object_id_control (p_obj_id_list => l_id_list);
FOR i IN l_id_list.FIRST .. l_id_list.LAST LOOP
DBMS_OUTPUT.put_line (l_id_list (i));
END LOOP;
END;

Related

PLS-00306: wrong number or types of arguments in call to procedure PROC_T

declare
TYPE stag_tab IS TABLE OF d_staging%ROWTYPE;
stag_tab1 stag_tab;
begin
--Bulk Collect
select * bulk collect into staging_tab1 from d_staging;
PKG_T.PROC_T(stag_tab1);
end;
/
Package definition:
--Package
CREATE OR REPLACE PACKAGE PKG_T
AS
TYPE staging IS TABLE OF d_staging%ROWTYPE;
PROCEDURE PROC_T(p_staging IN staging);
END PKG_T;
/
-- Package Body
CREATE OR REPLACE PACKAGE BODY PKG_T
AS
PROCEDURE PROC_T (p_staging IN staging)
AS
VAR1 d_staging%ROWTYPE;
CUR1 SYS_REFCURSOR;
QUERY_STRING VARCHAR2(2000);
BEGIN
OPEN CUR1 FOR SELECT * from table(p_staging);
LOOP
FETCH CUR1 into VAR1;
EXIT WHEN cur1%NOTFOUND;
INSERT into d (testdata) VALUES (var1.testval1);
COMMIT;
END LOOP;
END;
END PKG_T;
/
You are receiving the error because the procedure PKG_T.PROC_T is expecting a parameter of type staging, but when you are calling the procedure you are passing it a variable of type stag_tab. The type of the variable being passed to the procedure needs to match the type of the parameter definition for the procedure.
Your procedure declaration:
PROCEDURE PROC_T (p_staging IN staging)
Takes the argument as type staging.
You are passing the argument as a locally defined type:
TYPE stag_tab IS TABLE OF d_staging%ROWTYPE;
These are different types. Instead, you need the PL/SQL block to be:
declare
stag_tab1 package_name.staging;
begin
select *
bulk collect into stag_tab1
from d_staging;
PKG_T.PROC_T(stag_tab1);
end;
/

How to pass an array of values from Oracle Apex Page into Oracle stored procedure

I'm stuck with the passing Dates as an array parameters from the Oracle Apex page into package. Package contains one procedure with an array of type of dates. So what I want to do is to pass a simple dates into it from the Apex page, pl/sql block. Here is my code so far:
create or replace PACKAGE PK_NAME AS
TYPE DATES_ARRAY_TYPE IS VARRAY(100) OF DATE;
PROCEDURE PASS_DATES (
DATES DATES_ARRAY_TYPE
);
END PK_NAME;
create or replace PACKAGE BODY PK_NAME AS
PROCEDURE PASS_DATES (
DATES DATES_ARRAY_TYPE
) AS
BEGIN
for i in 1..DATES.count loop
HTP.P(DATES(i));
end loop;
END;
END PASS_DATES;
END PK_NAME;
Simple as that. And I call this procedure from the Apex page pl/sql block:
PK_NAME.PASS_DATES (
DATES => '15-JAN-15', '16-JAN-15', '17-JAN-15'
);
However, it doesn't work, every time I'm trying to save it, it gives me an error:
•ORA-06550: line 3, column 25: PLS-00312: a positional parameter association may not follow a named association ORA-06550: line 2, column 1: PL/SQL: Statement ignored
What is wrong with it or what have I missed ?
https://docs.oracle.com/cd/A97630_01/appdev.920/a96624/05_colls.htm
you must init constructor DATES_ARRAY_TYPE()
i think it must look like this
create TYPE DATES_ARRAY_TYPE IS VARRAY(100) OF DATE;
create or replace procedure test_case( p_dates DATES_ARRAY_TYPE) is
begin
dbms_output.put_line(p_dates(1));
end;
declare
a DATES_ARRAY_TYPE;
begin
a := DATES_ARRAY_TYPE(sysdate, sysdate + 1,to_date('1.01.2016','dd.mm.yyyy'));
test_case(a);
end;
also if you want to use TYPE in PACKAGE PK_NAME (not global) you must use object like PK_NAME.DATES_ARRAY_TYPE in your code.
ok, lets go in your case:
1. create package and body:
https://gyazo.com/789b875ce47852e859c395c2021f9cd4
create or replace PACKAGE PCK AS
-- your type in pck
TYPE DATES_ARRAY_TYPE IS VARRAY(100) OF DATE;
procedure test_case(p_dates DATES_ARRAY_TYPE);
END PCK;
create or replace PACKAGE body PCK AS
procedure test_case(p_dates DATES_ARRAY_TYPE) IS
BEGIN
--here just raise second element in array for DEMO
raise_application_error('-20000',p_dates(2) );
END;
END PCK;
2.create page and button and after submit process:
https://gyazo.com/755f6e089db0a6a8ea058567d2b3384b
declare
asd PCK.DATES_ARRAY_TYPE := PCK.DATES_ARRAY_TYPE('31-JUL-15', '01-AUG-15', '02-AUG-13', '03-AUG-13');
begin
pck.test_case(asd);
end;
after button that submit page i get this:
https://gyazo.com/b894fc6b9b6dd28964ba2e6548244bc8

PLSQL Procedure to return result set without a refcursor

So Im going trough an oracle database course and I have a homework where I have to create a procedure and "return" (I guess return) the resultset without using a refcursor, but all the examples I find make use of it.
So lets say I have this:
CREATE OR REPLACE PROCEDURE get_all_inventory() AS
BEGIN
SELECT * FROM Inventory;
END;
/
How do I make the procedure return the resultset without using refcursor?
is this even possible?
Thanks.
EDIT: If someone know a way of returning the result set in json that will be just awesome!
Aside from using JSON, you can also use collections as a return value. You have to create a package first for your procedure. Here's a sample code:
create OR REPLACE package get_all_inventory_package is
type arrayofrec is table of Inventory%rowtype index by pls_integer;
procedure get_all_inventory (o_return_variable OUT arrayofrec);
end;
/
create OR REPLACE package BODY get_all_inventory_package is
procedure get_all_inventory (o_return_variable OUT arrayofrec)is
return_variable arrayofrec;
begin
select * bulk collect into o_return_variable from Inventory;
end;
END;
/
declare
v_receiver get_all_inventory_package.arrayofrec;
begin
get_all_inventory_package.get_all_inventory(v_receiver);
for a in 1..v_receiver.count loop
dbms_output.put_line(v_receiver(a).Inventory_column);
end loop;
end;

How to create an oracle stored procedure with an array parameter

I créated an Oracle stored procedure into a package. I did like this:
CREATE OR REPLACE PACKAGE PACKFACE IS
TYPE LIST_IDS IS TABLE OF INT INDEX BY BINARY_INTEGER;
PROCEDURE P_SELECT_IDBFRIENDS (CONSULTA OUT SYS_REFCURSOR,COD_US IN INT,IDS_NOT IN LIST_IDS);
END;
And the body of the package is:
CREATE OR REPLACE PACKAGE BODY PACKFACE IS
PROCEDURE P_SELECT_IDBFRIENDS (CONSULTA OUT SYS_REFCURSOR,COD_US IN INT, IDS_NOT IN LIST_IDS) IS
BEGIN
OPEN CONSULTA FOR
SELECT ID_US1,ID_US2 FROM T_FRIENDSHIP WHERE ID_US1=COD_US AND ID_US2 NOT IN (SELECT COLUMN_VALUE FROM TABLE(IDS_NOT));
END;
END;
/
These is ok in my Oracle 12c server, but I did the same code in Oracle 11g appeared an error, cannot access rows from a non-nested table ítem. What would be the solution? Thanks in advance
After this problem was fixed. Appears other one my Python code was broken. I have this procedure:
def select_ids(self,cod_us,ids_not):
lista = []
try:
cursor = self.__cursor.var(cx_Oracle.CURSOR)
varray = self.__cursor.arrayvar(cx_Oracle.NUMBER,ids_not)
l_query = self.__cursor.callproc("PROC_SELECT_IDS_ENT_AMISTADES", [cursor, cod_us, varray])
lista = l_query[0]
return lista
except cx_Oracle.DatabaseError as ex:
error, = ex.args
print(error.message)
return lista
PLS-00306 wrong number or type of arguments in call to a procedure. It was ok using Oracle 12c. Thanks in advance again.
You cannot use a collection type defined in PL/SQL in an SQL query in Oracle 11.
If you want to use a collection in both SQL and PL/SQL then you will have to define it in SQL:
CREATE TYPE LIST_IDS IS TABLE OF INT;
Then you can do:
CREATE OR REPLACE PACKAGE PACKFACE IS
PROCEDURE P_SELECT_IDBFRIENDS (
CONSULTA OUT SYS_REFCURSOR,
COD_US IN INT,
IDS_NOT IN LIST_IDS
);
END;
/
SHOW ERRORS;
CREATE OR REPLACE PACKAGE BODY PACKFACE IS
PROCEDURE P_SELECT_IDBFRIENDS (
CONSULTA OUT SYS_REFCURSOR,
COD_US IN INT,
IDS_NOT IN LIST_IDS
)
IS
BEGIN
OPEN CONSULTA FOR
SELECT ID_US1,ID_US2
FROM T_FRIENDSHIP
WHERE ID_US1=COD_US
AND ID_US2 NOT MEMBER OF IDS_NOT;
END;
END;
/
SHOW ERRORS;
First of all you should to create an oracle type like this:
CREATE OR REPLACE TYPE LIST_IDS AS TABLE OF INT;
And after that you should to create the package with the procedure and a nested table in parameter like this:
CREATE OR REPLACE PACKAGE PACKFACE IS
TYPE LISTADO_IDS IS TABLE OF INT INDEX BY PLS_INTEGER;
PROCEDURE P_SELECT_IDBFRIENDS (CONSULTA OUT SYS_REFCURSOR,COD_US IN INT,IDS_NOT IN LISTADO_IDS);
END;
Finally you should create the body. You pass the data to nested table from oracle type like this:
CREATE OR REPLACE PACKAGE BODY PACKFACE IS
PROCEDURE P_SELECT_IDBFRIENDS (CONSULTA OUT SYS_REFCURSOR,COD_US IN INT, IDS_NOT IN LISTADO_IDS)
IS
num_array FACEBOOK.LIST_IDS;
BEGIN
num_array:=LIST_IDS();
for i in 1 .. IDS_NOT.count
loop
num_array.extend(1);
num_array(i) := IDS_NOT(i);
end loop;
OPEN CONSULTA FOR
SELECT ID_US1,ID_US2 FROM T_FRIENDSHIP WHERE ID_US1=COD_US AND ID_US2 NOT IN (SELECT COLUMN_VALUE FROM TABLE(num_array));
END;
END;
I did that and I got the solution to the python error wrong number or type parameters. Good luck.

pass pl/sql record as arguement to procedure

How to pass pl/sql record type to a procedure :
CREATE OR REPLACE PACKAGE BODY PKGDeleteNumber
AS
PROCEDURE deleteNumber (
list_of_numbers IN List_Numbers
)
IS
i_write VARCHAR2(5);
BEGIN
--do something
END deleteNumber;
END PKGDeleteNumber;
/
In this procedure deleteNumber I have used List_Numbers, which is a record type. The package declaration for the same is :
CREATE OR REPLACE PACKAGE PKGDeleteNumber
AS
TYPE List_Numbers IS RECORD (
IID NUMBER
);
TYPE list_of_numbers IS TABLE OF List_Numbers;
PROCEDURE deleteNumber (
list_of_numbers IN List_Numbers
);
END PKGDeleteNumber;
I have to execute the procedure deleteNumber passing a list of values. I inserted numbers in temp_test table, then using a cursor U fetched the data from it :
SELECT *
BULK COLLECT INTO test1
FROM temp_test;
Now, to call the procedure I am using
execute immediate 'begin PKGDELETENUMBER.DELETENUMBER(:1); end;'
using test1;
I have tried many other things as well(for loop, dbms_binding, etc). How do I pass a pl/sql record type as argument to the procedure?
EDIT:
Basically, I want to pass a list of numbers, using native dynamic sql only...
adding the table temp_test defn (no index or constraint):
create table test_temp (
IID number
);
and then inserted 1,2,3,4,5 using normal insert statements.
For this solution,
In a package testproc
CREATE TYPE num_tab_t IS TABLE OF NUMBER;
CREATE OR REPLACE PROCEDURE my_dyn_proc_test (p_num_array IN num_tab_t) AS
BEGIN
dbms_output.put_line(p_num_array.COUNT);
END;
/
this is called from sql prompt/toad
DECLARE
v_tab testproc.num_tab_t := testproc.num_tab_t(1, 10);
BEGIN
EXECUTE IMMEDIATE 'BEGIN testproc.my_dyn_proc_test(:1); END;' USING v_tab;
END;
this will not work.This shows error.I am not at my workstation so am not able to reproduce the issue now.
You can't use RECORD types in USING clause of EXECUTE IMMEDIATE statement. If you just want to pass a list of numbers, why don't you just use a variable of TABLE OF NUMBER type? Check below example:
CREATE TYPE num_tab_t IS TABLE OF NUMBER;
CREATE OR REPLACE PROCEDURE my_dyn_proc_test (p_num_array IN num_tab_t) AS
BEGIN
dbms_output.put_line(p_num_array.COUNT);
END;
/
DECLARE
v_tab num_tab_t := num_tab_t(1, 10);
BEGIN
EXECUTE IMMEDIATE 'BEGIN my_dyn_proc_test(:1); END;' USING v_tab;
END;
Output:
2
Edit
Try this:
CREATE TYPE num_tab_t IS TABLE OF NUMBER;
CREATE OR REPLACE PACKAGE testproc AS
PROCEDURE my_dyn_proc_test (p_num_array IN num_tab_t);
END;
/
CREATE OR REPLACE PACKAGE BODY testproc AS
PROCEDURE my_dyn_proc_test (p_num_array IN num_tab_t) AS
BEGIN
dbms_output.put_line(p_num_array.COUNT);
END;
END;
/
DECLARE
v_tab num_tab_t := num_tab_t(1, 10);
BEGIN
EXECUTE IMMEDIATE 'BEGIN testproc.my_dyn_proc_test(:1); END;' USING v_tab;
END;
Use an object type. object types are visible to all packages

Resources