Sending multiple sets of parameters to procedure - vb.net

I'm using vb.net and oracle db, and currently I have a stored-procedure that is called from my code. Right now it looks similar to this:
CREATE OR REPLACE PROCEDURE MYPROCEDURE(
param1 table.field1%TYPE,
param2 table.field2%TYPE,
param3 table.field3%TYPE,
param4 varchar2,
output OUT number) AS
BEGIN
DO STUFF
END;
I want to ask if it is possible to change this to send multiple sets of parameters at once, so I could use a FOR LOOP inside my procedure to minimize the number of calls. I want to achieve something like this:
CREATE OR REPLACE PROCEDURE MYPROCEDURE(
param myArray
output OUT number) AS
BEGIN
FOR i IN 1..myArray.COUNT LOOP
UPDATE FIELD FROM TABLE WHERE ID = myArray(i).field1;
END LOOP;
END;
Or if there's anything else that would work the same it would be great.
Many thanks.

Yes you can pass a list of objects as parameter in oracle procedure. First you must create the datatype of this list of objects, but you can't do this inside a procedure you have to define it as an oracle object. For example:
CREATE OR REPLACE TYPE TEST."MY_TYPE" AS OBJECT
(PARAM1 VARCHAR (20), PARAM2 NUMBER);
Unfortunately you can define dynamic datatypes inside objects (table.field1%TYPE), but I think you know what datatype this field have.
Second, create a package that have the list of parameter and procedure definition like this:
CREATE OR REPLACE PACKAGE ARRAY_EXAMPLE2
AS
TYPE COL IS TABLE OF MY_TYPE;
PROCEDURE PROCESS_ARRAY (ArrayIn IN COL);
END;
And finally the package implementation
CREATE OR REPLACE PACKAGE BODY ARRAY_EXAMPLE2
AS
PROCEDURE PROCESS_ARRAY (ArrayIn IN COL)
IS
BEGIN
FOR i IN 1 .. ArrayIn.COUNT
LOOP
DBMS_OUTPUT.PUT_LINE ('Hello ' || ArrayIn (i).PARAM1);
END LOOP;
END;
END;
You can try it using this lines of code:
BEGIN
ARRAY_EXAMPLE2.
PROCESS_ARRAY (
array_example2.
COL (MY_TYPE ('Peter', 12),
MY_TYPE ('Jorge', 4),
MY_TYPE ('Bryan', 5)));
END;

Related

PL/SQL OUT SYS_REFCURSOR on associative array

I have an associative array inside a procedure:
create or replace PROCEDURE RET_STRING_TAB(o_cursor OUT SYS_REFCURSOR) IS
type type_ntz is record(type_id number, type_uname varchar(32), type_pwd varchar(16));
type ntz_array is table of type_ntz index by pls_Integer;
v_ntz_array ntz_array;
BEGIN
Select id,uname,pwd BULK COLLECT INTO v_ntz_array FROM users;
As you can see i want to out a refcusor on that array, to work further in Java with it. I tried doing:
OPEN o_cursor FOR
SELECT * FROM TABLE(v_ntz_array);
But it keeps saying:
PL/SQL: SQL Statement ignored
PL/SQL: cannot access rows from a non-nested table item
PLS: expression is of wrong type
Thanks in advance for any help!
You TYPE needs to be create out of the procedure, so your calling program (ie: java) can access it and know it's composition:
CREATE OR REPLACE TYPE type_ntz IS OBJECT(type_id number, type_uname varchar(32), type_pwd varchar(16));
/
then:
create or replace PROCEDURE RET_STRING_TAB(o_cursor OUT SYS_REFCURSOR) IS [...]
UPDATE
I've re-read your question and for me the easiest way to do what you are looking for is:
create or replace PROCEDURE RET_STRING_TAB(o_cursor OUT SYS_REFCURSOR) IS
BEGIN
OPEN o_cursor FOR
Select id,uname,pwd FROM users;
END;
/

Redshift dollar quoting inside a procedure

I have a procedure which accepts the table name and the 3 fields that need filling. This is to be called from another procedure that loops through another table deciding which sub-table to put stuff into. The important bit is a simple insert statement, e.g.
insert into table1 values
('blah','String','50');
So that 4 parameters coming in (table1, and the 3 values). How would I do this using dollar quoting? Obviously this doesnt work but gives you an idea of what I'm trying to accomplish:
create or replace procedure
insert_dc_table(p_tblname varchar,
p_name varchar,
p_datatype varchar,
p_datalen varchar)
as $$
begin
execute
'insert into '||p_tblname||'(name,datatype,datalen) values '
||'('
||p_name||', '
||p_datatype||', '
||p_datalen
||')';
end;
$$ language plpgsql;
I'd need double-dollars around some, but am unsure of exactly where $$ and quotes go in all this !*&#!
I could declare a variable to hold the execute statement and do:
declare a _output varchar(200);
a_output := $$ insert into $$||p_tblname||$$(name,datatype,datalen) values ( '$$||p_name||$$',
well, i get lost there!
Thanks in advance for help!
Redshift Stored Procedures only require dollar quoting of the procedure body. Quotes inside the the procedure body are interpreted as normal.
You may find that your SQL client does not submit the SP create correctly due to the dollar quotes. If so I recommend using psql to create the stored procedure.
Sample stored procedures are available in our "Amazon Redshift Utils" GitHub repository.
Here's a modification of your example:
-- DROP PROCEDURE insert_dc_table(VARCHAR,VARCHAR ,VARCHAR ,VARCHAR);
CREATE OR REPLACE PROCEDURE insert_dc_table(
p_tblname VARCHAR, p_name VARCHAR, p_datatype VARCHAR, p_datalen VARCHAR )
AS $$
DECLARE
rows INTEGER;
BEGIN
sql := 'INSERT INTO '||p_tblname||' (name, datatype, datalen)'
||' VALUES ('||p_name||','||p_datatype||','||p_datalen||');';
RAISE INFO 'Running SQL: %', sql;
EXECUTE sql;
GET DIAGNOSTICS rows := ROW_COUNT;
RAISE INFO 'Rows inserted = %', rows;
END
$$ LANGUAGE plpgsql;
-- CALL insert_dc_table ('test_table', 'name', 'type', 'length');

Oracle SQL Developer, using dynamic SQL in function

I have the following script which contains a function named 'myFunction'. (declaration of types named rowValueTmp and rowValueTable are also attached for your information) Basically, I need to use a table name as an input parameter for myFunction. I found that I need to use dynamic SQL in order to use the table name as a parameter (Please correct me if there are alternative ways to do this). So the following code is what I have tried so far.
create or replace type rowValueTmp as object (
month number,
year number
);
/
create or replace type rowValueTable as table of rowValueTmp;
/
create or replace FUNCTION myFunction (TABLENAME in VARCHAR2)
return rowValueTable as
v_ret rowValueTable;
begin
execute immediate '
select rowValueTmp(month, year)
bulk collect into v_ret
from '||TABLENAME;
return v_ret;
end myFunction;
/
select * from table(myFunction('SCHEMA.TEST'));
But, this code gives me an error, and I assumed that this error is occurred because of using 'bulk collect' in execute immediate block.
ORA-03001: unimplemented feature
If I replace the content of execute immediate as the following, the above script is working..
select rowValueTmp(month, year)
bulk collect into v_ret
from SCHEMA.TEST;
Question
1] Is there any way(rather than Dynamic SQL) that I can use a table name as an input parameter for myFunction?
2] If I am not allowed to use bulk collect in execute immediate block, what do you suggest?
You can return values from execute immediately into a bulk collect:
CREATE OR REPLACE FUNCTION myfunction (tablename IN VARCHAR2)
RETURN rowvaluetable AS
v_ret rowvaluetable;
v_table VARCHAR2 (61) := DBMS_ASSERT.sql_object_name (tablename);
BEGIN
EXECUTE IMMEDIATE '
select rowValueTmp(month, year)
from ' || v_table
BULK COLLECT INTO v_ret;
RETURN v_ret;
END myfunction;
/
In the interest of an abundance of caution, I'd recommend using DBMS_ASSERT to validate the table parameter as well (as shown).

How to execute a stored procedure with cursor and table OUT parameters through SQL Developer?

I’m having trouble testing, in SQL Developer 3.2.20.09, an Oracle stored procedure that contains 2 specificities:
a user defined "cursor type" output parameter
a user defined "TABLE OF VARCHAR type" output parameter.
Stored procedure signature:
TYPE ref_cursor_tst IS REF CURSOR;
TYPE arrWarningCode_tst IS TABLE OF VARCHAR2 (4000)
INDEX BY BINARY_INTEGER;
PROCEDURE SP_ITF_CU_DOCUMENT_Test (
p_projectNumber IN VARCHAR2,
p_tag IN VARCHAR2,
p_title IN VARCHAR2,
out_document_curs OUT ref_cursor_tst,
out_errorCode OUT VARCHAR2,
out_arrWarningCode OUT arrWarningCode_tst);
My actual best test code I could end up with:
set serveroutput on size 100000
DECLARE
docRef VARCHAR2(200);
outDocCurs PD360BADMIN.PKG_ITF_GENERAL_TST.ref_cursor_tst;
outErrorCode VARCHAR2(2000);
arrWarningCodes PD360BADMIN.PKG_ITF_GENERAL_TST.arrWarningCode_tst;
i PLS_INTEGER;
doc TBL_OBJECT%ROWTYPE;
BEGIN
dbms_output.put_line('debut de procedure');
docRef:= 'DOC-012';
arrWarningCodes.DELETE;
--call SP
PKG_ITF_GENERAL_TST.SP_ITF_CU_DOCUMENT_TEST (
p_projectNumber => 'XXX',
p_tag => docRef,
p_title => 'Doc title',
out_document_curs => outDocCurs,
out_errorCode => outErrorCode,
out_arrWarningCode => arrWarningCodes);
--print error code
dbms_output.put_line('out_errorCode=' || outErrorCode);
--print output cursor
--dbms_output.put_line(outDocCurs);
LOOP
FETCH outDocCurs INTO doc;
EXIT WHEN outDocCurs%NOTFOUND;
dbms_output.put_line(doc.OBJ_ID||','||doc.OBJ_TAG);
END LOOP;
--print warnings array
IF arrWarningCodes.count > 0 THEN
FOR i IN arrWarningCodes.FIRST .. arrWarningCodes.LAST LOOP
dbms_output.put_line('warning code=' || arrWarningCodes(i) );
END LOOP;
ENd IF;
dbms_output.put_line('fin de procedure');
END;
/
The error I get:
Error report:
ORA-06504: PL/SQL: Return types of Result Set variables or query do not match
ORA-06512: at line 30
06504. 00000 - "PL/SQL: Return types of Result Set variables or query do not match"
*Cause: Number and/or types of columns in a query does not match declared
return type of a result set variable, or declared types of two Result
Set variables do not match.
*Action: Change the program statement or declaration. Verify what query the variable
actually refers to during execution.
debut de procedure
out_errorCode=
I've been testing various solutions and syntaxes for days as well as digging the net and requiring help from different sources with no success.
Any clue would be much appreciated.
Assuming TBL_OBJECT is a table of some object type which has the two fields obj_id and obj_tag; and the procedure is currently doing something like:
open out_document_curs for select * from tbl_object;
... then there are two ways to make this work. The first is to change the variables you're fetching into to match the object fields, rather than the object itself:
DECLARE
...
-- doc TBL_OBJECT%ROWTYPE;
doc_obj_id TBL_OBJECT.OBJ_ID%TYPE;
doc_obj_tag TBL_OBJECT.OBJ_TAG%TYPE;
BEGIN
...
and then change the fetch and display:
LOOP
FETCH outDocCurs INTO doc_obj_id, doc_obj_tag;
EXIT WHEN outDocCurs%NOTFOUND;
dbms_output.put_line(doc_obj_id||','||doc_obj_tag);
END LOOP;
If the object has more fields then you'd need to define them all and specify them in the fetch too.
The other is to modify the procedure so that it returns an object type:
open out_document_curs for select value(t) from tbl_object t;
Then your calling anonymous block will work as it is, as the simple query will return the object itself rather than the fields within it.
Which you do will depend on how the procedure will really be used, rather than your test call.
With some dummy set-up:
create type doc_obj as object (obj_id number, obj_tag varchar2(10));
/
create table tbl_object of doc_obj;
insert into tbl_object values (doc_obj(1, 'Test'));
And a dummy package body with the procedure simplified as:
PROCEDURE SP_ITF_CU_DOCUMENT_Test (
p_projectNumber IN VARCHAR2,
p_tag IN VARCHAR2,
p_title IN VARCHAR2,
out_document_curs OUT ref_cursor_tst,
out_errorCode OUT VARCHAR2,
out_arrWarningCode OUT arrWarningCode_tst)
IS
BEGIN
open out_document_curs for select value(o) from tbl_object o;
out_errorCode := 'OK';
out_arrWarningCode(1) := 'Danger!';
END SP_ITF_CU_DOCUMENT_Test;
Then calling your code exactly as you have it in the question (minus the schema name) gives:
anonymous block completed
debut de procedure
out_errorCode=OK
1,Test
warning code=Danger!
fin de procedure
Using the other approach, with the individual variables for the object fields, gives the same result too.

Oracle-Form assign value to user-defined type

I'm creating an (stored) user-defined type on database level:
CREATE OR REPLACE TYPE Some_Text AS VARRAY(20) OF VARCHAR2(50);
Then there is a (stored) procedure that using this user-defined type:
CREATE OR REPLACE PROCEDURE Test_Procedure(
p_to IN Some_Text,
p_from IN Some_Text
--some code here--
)
On form-level (Form Builder), I created a datablock with tabular (5 text-items).
On this text-item user can enter some text. Then this text will be used as parameter when calling procedure "Test_Procedure". How to do that?
I could call the procedure with this code:
Test_Procedure
(Some_Text('bla', 'bla', 'bla'),
Some_Text('bla', 'bla', 'bla'));
But, I don't know how to do that with datablock.text-item.
Note:
I'm still very new to oracle, so please bear with me.
Thanks before.
You can loop through the block to construct the varray.
Ex.
declare
i number := 0
begin
go_block('myblock');
first_record;
loop
exit when :system.last_record = 'TRUE';
i := i + 1;
some_text(i) := :myblock.mytextitem;
next_record;
end loop;
end;