call a procedure with table as IN parameters - oracle

I have the following code which works very nice:
declare
v_order_id oe.orders.order_id%type := 1;
v_order_item pkg_order_management.to_order_list := pkg_order_management.to_order_list();
begin
v_order_item.extend(2);
v_order_item(1).product_id := 2289;
v_order_item(1).quantity := 2;
v_order_item(2).product_id := 2058;
v_order_item(2).quantity := 5;
pkg_order_management.prc_create_order(240, v_order_item, v_order_id);
dbms_output.put_line('it was created the order: ' || v_order_id);
end;
but I want to call the pkg_order_management.prc_create_order procedure like
declare
v_order_id oe.orders.order_id%type := 1;
begin
pkg_order_management.prc_create_order(240, ((2289, 2),(2058, 5)), v_order_id);
dbms_output.put_line('it was created the order: ' || v_order_id);
end;
Here is the types definition from the package:
type t_order_item is record
( product_id oe.order_items.product_id%type
, quantity oe.order_items.quantity%type);
type to_order_list is table of t_order_item;
When I call the procedure as in 2nd case, I receive the following error:
PLS-00306: wrong number or types of arguments in call to
'PRC_CREATE_ORDER'
Surely, my call type is wrong but I have no idea how to solve this.
Can you give me a hint, please?

PL/SQL record types are not object-oriented constructs. So we can't use them as flexibly as we can actually Objects.
If you want to pass an inline array you need to define your types using SQL:
create or replace type t_order_item is object
( product_id number
, quantity number);
/
create or replace type to_order_list is table of t_order_item;
/
Note that this means you can no longer use %TYPE referencing to define the attributes of t_order_item.
Now your call to the procedure will look like this:
begin
pkg_order_management.prc_create_order(240
, to_order_list(t_order_item(2289, 2)
, t_order_item(2058, 5)
), v_order_id);
end;
/

The proper call would be this:
pkg_order_management.prc_create_order(
240,
pkg_order_management.to_order_list(
t_order_item(2289, 2),
t_order_item(2058, 5)
),
v_order_id
);
... but do you really want such an ugly code?
pkg_order_management.prc_create_order(240, v_order_item, v_order_id); looks more beautiful to me.

You need to use OBJECT not RECORD.
Please red this:
https://docs.oracle.com/cd/B19306_01/appdev.102/b14261/objects.htm
Then you can use this nice notation:
CREATE TYPE t_order_item AS OBJECT (
product_id NUMBER,
quantity NUMBER
);
/
CREATE TYPE to_order_list IS TABLE OF t_order_item;
/
DECLARE
v_order_id NUMBER;
PROCEDURE prc_create_order (a NUMBER, order_list to_order_list, o_order_id OUT NUMBER)
IS
BEGIN
NULL;
END;
BEGIN
prc_create_order(240, to_order_list(
t_order_item(2289, 2),
t_order_item(2058, 5)
)
, v_order_id);
END;
/

Related

plsql printing a custom object

I am having issues in printing the custom object.
Here is my complete use case
create or replace type invoice_obt
as object (
invoice_id number
);
/
create type invoices_ntt
as table of invoice_obt;
/
create type customer_with_invoices
as object (
customer_id number,
invoices invoices_ntt
)
declare
l_customer customer_with_invoices;
l_invoices invoices_ntt := invoices_ntt();
begin
l_invoices.extend(3);
l_invoices(1) := invoice_obt(100);
l_invoices(2) := invoice_obt(200);
l_invoices(3) := invoice_obt(200);
l_customer := customer_with_invoices(1,l_invoices);
end;
How do i print out the l_customer using dbms_output please.
When you call customer_with_invoices(), you want to call the constructor, so you need to pass parameters for the object properties, even null if you want.
Also, the extend applies to l_customers.invoices, and not to l_customers.
For example, this works:
declare
l_customers customer_with_invoices := customer_with_invoices(null, null);
begin
l_customers.invoices := invoices_ntt();
l_customers.invoices.extend(1);
l_customers.invoices(1) := new invoice_obt(1);
--
dbms_output.put_line(l_customers.invoices(1).invoice_id);
end;
/
To print the content of the object with dbms_output.put_line , you need to pass it the elements, given that it does not handle objects. In your edited code, this is an example:
for i in 1 .. l_customer.invoices.count loop
dbms_output.put_line('invoice (' || i || ') = ' || l_customer.invoices(i).invoice_id);
end loop;
In a production code, you should better check if objects exist, before trying to use .count or similar.

How to execute procedure with input parametr (Varray OF INT)?

CREATE OR REPLACE TYPE list_of_int IS
VARRAY(10) OF INT;
CREATE OR REPLACE PROCEDURE my_procedure(
in_lista in list_of_int
)
AS
...
exec my_procedure( [1,2,3] );
How to execute procedure with input parametr VARRAY?
You can do something like this
CREATE OR REPLACE TYPE list_of_int IS
VARRAY(10) OF INT;
/
CREATE OR REPLACE PROCEDURE my_procedure(
in_lista in list_of_int
)
AS
begin
for i in 1..in_lista.count
loop
dbms_output.put_line( in_lista(i) );
end loop;
end;
/
exec my_procedure( list_of_int(1, 2, 3) );
/
Practically, though, I have yet to encounter an instance where it made sense to declare a varray type. It would almost certainly make more sense to declare a nested table type which doesn't limit the number of elements you can have in your collection (well, I think you're limited to 2^32 or whatever you can fit in PGA but if you're doing something seriously wrong if you get close to that). I can't think of a situation where I'd want to have code that intentionally dies if someone wants to pass an 11 element list.
CREATE OR REPLACE TYPE int_t IS
table OF INT;
/
CREATE OR REPLACE PROCEDURE my_procedure(
in_lista in int_t
)
AS
begin
for i in 1..in_lista.count
loop
dbms_output.put_line( in_lista(i) );
end loop;
end;
/
exec my_procedure( int_t(1, 2, 3) );
/

Calling procedure in function

Can you call a PL/SQL procedure from inside a function?
I haven't come across with the practical example.So if anyone has come across with this please share.
Yes. You can call any pl/sql program from inside any other pl/sql program. A function can call a function, a procedure can call a procedure which calls a function, a function can invoke a TYPE BODY...do an INSERT..which causes a TRIGGER to fire.
A simple (not really practical) example.
Using the HR schema where you have an EMPLOYEES table which includes columns EMPLOYEE_ID, FIRST_NAME, and LAST_NAME.
I have a function that takes in an INTEGER which we use to look up an EMPLOYEE record. We take their first and last names, and concat them together, and return the value back in UPPERCASE text.
Before we do that however, we call a procedure which does nothing but take a 5 second nap using the DBMS_LOCK package.
The code:
create or replace procedure do_nothing_comments (x in integer, y in integer)
is
begin
null;
-- yeah, this is a dumb demo
dbms_lock.sleep(5);
end;
/
create or replace FUNCTION upper_name (
x IN INTEGER
) RETURN VARCHAR2 IS
upper_first_and_last VARCHAR2 (256);
BEGIN
SELECT upper (first_name)
|| ' '
|| upper (last_name)
INTO upper_first_and_last
FROM employees
WHERE employee_id = x;
do_nothing_comments (1, 2); -- here we are calling the procedure
RETURN upper_first_and_last;
END;
/
Now let's invoke the function.
DECLARE
X NUMBER;
v_Return VARCHAR2(200);
BEGIN
X := 101;
v_Return := UPPER_NAME(
X => X
);
:v_Return := v_Return;
END;
/
I'm going to do this in SQL Developer using the Execute feature with the function open:
I get the answer back...it just takes 5 seconds longer than it really needed to.
Here you go:
create or replace function demo
return varchar2
as
begin
dbms_output.put_line('Hello');
return 1;
end demo;

How to pass NUMBER_LIST_TYPE IN parameter to ORACLE stored procedure

I have a stored procedure like this:
Create or replace procedure readEmpDetails (empRowList NUMBER_LIST_TYPE,
created_by VARCHAR2,
accessid NUMBER )
is
How can I pass parameter for NUMBER_LIST_TYPE:
begin readEmpDetails([124, 155, 147], '100', 2); end;
I want to pass parameter like above in Oracle SQL Developer.
Do the below steps:
create or replace type T_array_readEmpDetails AS VARRAY(10) of number(4)
/
Create or replace procedure readEmpDetails (t_ar T_array_readEmpDetails,
created_by VARCHAR2,
accessid NUMBER )
is
begin
FOR i IN 1..t_ar.count LOOP
dbms_output.put_line(t_ar(i));
END LOOP;
end;
/
DECLARE
v T_array_readEmpDetails;
BEGIN
v := T_array_readEmpDetails();
v.EXTEND(3);
v(1) := 124;
v(2) := 155;
v(3) := 147;
readEmpDetails(v,'A',1);
END;
/
If NUMBER_LIST_TYPE is a valid oracle type, you pass it as NUMBER_LIST_TYPE(124, 155, 147).
Then you are creating an instance of the type with 3 Elements "on the fly".

Handle the result of procedure A in procedure B

I have procedure A, which has some in and out parameters. I can't change parameters or code of first procedure, but I need to get different result. I decided to create procedure B, which will pass additional parameter. I want to call procedure A from this procedure and handle result of procedure A in it. I know type of parameters, which procedure A returns.
I need somethink like this:
procedure A(id in number, names out names_array) is
begin
// procedure A body
// filling names var
end;
procedure B (id in number, myLimit in number, names out names_array) is
temp_names names_array;
i integer;
begin
A(id => id, names => temp_names);
while i < myLimit loop
names(i) := temp_names(i);
end loop;
end;
So the problem is in handling names (the result of procedure A). How I can do this correctly? Maybe with some select ... limit myLimit query?
Definition of names_array:
TYPE names_array IS TABLE OF VARCHAR2 (40)
INDEX BY BINARY_INTEGER;

Resources