pass pl/sql record as arguement to procedure - oracle

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

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;
/

Executing a query using a Collection as argument in Oracle

Is there any way I can execute immediate a query with a collection as its argument.
I want to define a type as type my_type as table of number and then execute a dynamic query (created by concating proper parts) using execute immediate QUERY using COLLECTION.
When I write such a code I get PLS-00457 expressions has to be of SQL types.
From oracle documentation :https://docs.oracle.com/cd/B12037_01/appdev.101/b10807/11_dynam.htm
Example 7-4 Dynamic SQL for Object Types and Collections
The below example illustrates the use of objects and collections. Suppose you define object type Person and VARRAY type Hobbies, as follows:
CREATE TYPE Person AS OBJECT (name VARCHAR2(25), age NUMBER);
CREATE TYPE Hobbies IS VARRAY(10) OF VARCHAR2(25);
Using dynamic SQL, you can write a package that uses these types:
CREATE OR REPLACE PACKAGE teams AS
PROCEDURE create_table (tab_name VARCHAR2);
PROCEDURE insert_row (tab_name VARCHAR2, p Person, h Hobbies);
PROCEDURE print_table (tab_name VARCHAR2);
END;
/
CREATE OR REPLACE PACKAGE BODY teams AS
PROCEDURE create_table (tab_name VARCHAR2) IS
BEGIN
EXECUTE IMMEDIATE 'CREATE TABLE ' || tab_name ||
' (pers Person, hobbs Hobbies)';
END;
PROCEDURE insert_row (
tab_name VARCHAR2,
p Person,
h Hobbies) IS
BEGIN
EXECUTE IMMEDIATE 'INSERT INTO ' || tab_name ||
' VALUES (:1, :2)' USING p, h;
END;
PROCEDURE print_table (tab_name VARCHAR2) IS
TYPE RefCurTyp IS REF CURSOR;
cv RefCurTyp;
p Person;
h Hobbies;
BEGIN
OPEN cv FOR 'SELECT pers, hobbs FROM ' || tab_name;
LOOP
FETCH cv INTO p, h;
EXIT WHEN cv%NOTFOUND;
-- print attributes of 'p' and elements of 'h'
END LOOP;
CLOSE cv;
END;
END;
/
From an anonymous block, you might call the procedures in package TEAMS:
DECLARE
team_name VARCHAR2(15);
BEGIN
team_name := 'Notables';
teams.create_table(team_name);
teams.insert_row(team_name, Person('John', 31),
Hobbies('skiing', 'coin collecting', 'tennis'));
teams.insert_row(team_name, Person('Mary', 28),
Hobbies('golf', 'quilting', 'rock climbing'));
teams.print_table(team_name);
END;
/
Yes, you can do that but
1) type should be defined as OBJECT
2) Oracle version should be 11g or higher
3) if your dynamic block has plsql code, you can assign this collection value inside dynamic block variable and then use it
4) if your dynamic block is just some sql, you need to cast the collection to table first using Table(collection) keyword

call plsql procedure with parameters

I tried to call this procedure but have some issues
CREATE OR REPLACE Procedure InsertNewReservation
( flight_number IN varchar2,passenger_id IN number,flight_price in number )
IS
s2 number;
BEGIN
insert into Reservations (flightNumber,passengerId) values (flight_number,passenger_id)
returning ID into s2;
insert into Payments (value,reservationId) values (flight_price,s2);
END;
/
How do I call the procedure ?
I tried
BEGIN
InsertNewReservation('FL100',1,120);
END;
/
But it didn't work :/
Thanks!
Because there's no ID column, but passengerId within the Reservations table :
CREATE OR REPLACE Procedure InsertNewReservation
(
flight_number Reservations.flightNumber%type,
passenger_id Reservations.passengerId%type,
flight_price Payments.value%type
)
IS
s2 Payments.reservationId%type;
BEGIN
insert into Reservations (flightNumber,passengerId)
values(flight_number,passenger_id) returning passengerId into s2;
insert into Payments (value,reservationId) Values (flight_price,s2);
END;
/
btw, replace the variables so as to conform their respective types within the table, and using IN operator is redundant for parameter type of the procedure as being the default.
Demo
Remove the exec keyword, which is not used in a PL/SQL block:
begin
InsertNewReservation('FL100',1,120);
end;
exec is used in tools like SQL Plus to run a procedure outside a PL/SQL block:
SQL> exec InsertNewReservation('FL100',1,120);

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

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;

Pl/sql Executing procedures

I am totally new to PL/SQL.
create or replace procedure p1(a in customer.id%type,
b out customer.name%type,
c out customer.dept%type)
is
begin
select name,dept into b,c from customer where id=a;
end;
Its created properly.
But I am not sure how to execute it.
EXEC p1(1);
But this is showing error.
Your procedure has three parameters so you'd need to call it with three parameters. In the case of OUT parameters, you need to pass in variables that will hold the values that are being returned by the procedure.
DECLARE
l_id customer.id%type := 1;
l_name customer.name%type;
l_dept customer.dept%type;
BEGIN
p1( l_id, l_name, l_dept );
<<do something with l_name and l_dept>>
END;
/
There are two ways to execute a procedure.
From the SQL prompt.
EXECUTE [or EXEC] procedure_name;
Within another procedure – simply use the procedure name.
procedure_name;
the procedure have 3 parameters, you can't call it like p1(1) using just one parameter
in your case try something like this
DECLARE
p_name customer.name%type;
p_department customer.dept%type;
BEGIN
p1(1, p_name, p_department);
END;
Output parameters should be stored in variables.
Input, can be variables or directly given in between the ( )
Use dbms_output.put_line to easily show output in your IDE.
DECLARE
p_name customer.name%type;
p_department customer.dept%type;
p_id customer.id%type := 1;
BEGIN
p1(p_id, p_name, p_department);
END;

Resources