问题
I am attempting to create a really simple procedure that creates an account or several accounts. In order to accomplish this I wanted the implementation of the Call that will be made to this Procedure to be as simple as possible. The Code behind the Procedure can be complex or simple but that's not entirely what I care about here as I'm approaching this first from the perspective of the User that will be making the Call to the create_account() Proc.
Simple Call to Create an Account - As you can see in the code I provided there are Zero Declarations... I'm not initializing anything when making the Call. This is important to maximize the level of simplicity regarding the usage of this Procedure.
BEGIN
create_account(p_entity_id => 550005
, p_sub_id => 100051
, v_contacts_fname => sys.odcivarchar2list('dan','bob')
, v_contacts_lname => sys.odcivarchar2list('anderson','bebop')
);
END;
Basically, I'm looking for the easiest route to allow a user to just type into this call a simple list of comma separated values via an array which will then be parsed in order to perform an insert into an accounts table.
The issue: Since I'm currently taking into the Procedure two collections how do I tie together the entries by index..? Index 1 of Collection 1 should tie to Index 1 of Collection 2 and so on. What is the best approach to make this connection within the PL/SQL contained in the create_account() Procedure?
Ideally I would have loved to be able to do something similar as can be done in C# which would be to just New Up a LIST() Object without the requirement of Declaring that object and to just send that into the Procedure or some sort of multi column array however I'm unable to just send a RECORD Type directly into the Procedure which is why I thought that using the sys.odcivarchar2list collections Oracle provides could work. This approach does allow me to create collections based on my basic comma separated values but they are ONLY single column collections and so I must use Two collections for each of the two parameters I care about here. Eventually I will like to scale up the parameters to include account_type, phone_numbers etc... but I first need to discover the BEST way to tie these collections together based on the index.
See below the work I have begun so far. FULL Script/Code - Very basic but it gets the point across.
/* This code will run on it's own. Single PL/SQL Block. */
DECLARE
PROCEDURE create_account(p_entity_id NUMBER
, p_sub_id NUMBER
, v_contacts_fname sys.odcivarchar2list
, v_contacts_lname sys.odcivarchar2list
)
IS
BEGIN
dbms_output.put_line('Entity_id: ' || p_entity_id || ' - Sub_id: ' || p_sub_id);
FOR f IN (SELECT m.column_value fname FROM TABLE(v_contacts_fname) m)
LOOP
FOR l IN (SELECT m.column_value lname FROM TABLE(v_contacts_lname) m)
LOOP
dbms_output.put_line(l.lname ||', ' || f.fname);
END LOOP;
END LOOP;
END create_account;
BEGIN
create_account(p_entity_id => 550005
, p_sub_id => 100051
, v_contacts_fname => sys.odcivarchar2list('dan','bob')
, v_contacts_lname => sys.odcivarchar2list('anderson','bebop')
) ;
END;
Output
/* I just thru a dbms_output() within both loops for display but of course this is NOT */
/* how I want to tie together the entries of both collections to each other */
Entity_id: 550005 - Sub_id: 100051
anderson, dan
bebop, dan
anderson, bob
bebop, bob
The correct Output of course would be:
anderson, dan
bebop, bob
回答1:
The collection type you are using is a varray, so it is indexed; you can do:
FOR i IN 1..v_contacts_fname.COUNT
LOOP
dbms_output.put_line(v_contacts_fname(i) ||', ' || v_contacts_lname(i));
END LOOP;
Adapting your example code:
DECLARE
PROCEDURE create_account(p_entity_id NUMBER
, p_sub_id NUMBER
, v_contacts_fname sys.odcivarchar2list
, v_contacts_lname sys.odcivarchar2list
)
IS
BEGIN
dbms_output.put_line('Entity_id: ' || p_entity_id || ' - Sub_id: ' || p_sub_id);
FOR i IN 1..v_contacts_fname.COUNT
LOOP
dbms_output.put_line(v_contacts_fname(i) ||', ' || v_contacts_lname(i));
END LOOP;
END create_account;
BEGIN
create_account(p_entity_id => 550005
, p_sub_id => 100051
, v_contacts_fname => sys.odcivarchar2list('dan','bob')
, v_contacts_lname => sys.odcivarchar2list('anderson','bebop')
) ;
END;
/
now gets
Entity_id: 550005 - Sub_id: 100051
dan, anderson
bob, bebop
PL/SQL procedure successfully completed.
You could do a very basic check at the start to verify that the count from both arrays is the same - if not then throw an exception perhaps.
If you want to pass a single collection argument then that argument would need to be a collection of record or object types, declared either at schema level or perhaps in a package, depending on how you want to use the contents (and, to some extent, the version of Oracle you are using). It sounds like you don't want to do that though.
来源:https://stackoverflow.com/questions/56675046/how-to-work-with-pl-sql-arrays-or-collections-as-parameters-then-join-them-toget