Run functions recursively - function

I have 2 function function1 and function2.
Now I'm wondering how to run them recursively.
Maybe I will describe it:
Input of function1 is table of array from function2 output. Output of function1 is also table of array which is input for function2 and so on.
While function1 is returning some values then function2 should be execute with that values.
When function2 return some values then function1 should be execute.
Function1 and function2 should be execute until one of them return null. Is it possible to do in pl/sql? Could you give me some tips? How to correctly convey the variables?
EDIT:
Generally it should looks:
declare
tab2 num_array;
v_Return NUM_ARRAY;
v_Return2 NUM_ARRAY;
BEGIN
select ID bulk collect into tab2 from account;
v_Return := function1(tab2);
if v_return is not null then
v_return2 :=function2(v_return);
--and now iteration:
if v_return2.count>0 then
v_Return := function1(v_return2);
if v_return.count>0 then
v_return2 :=function2(v_return);
if v_return2.count>0 then
v_Return := function1(v_return2);
if v_return..count>0 then
v_return2 :=function2(v_return);
-- and so on
END;
Of course I want to avoid doing something like that, can it be dynamically?
----edit 2
while(num=1)
loop
if v_return.count>0 then
num := 1;
v_return2 :=function2(v_return);
if v_return2.count>0 then
num :=1;
v_Return := function1(v_return2);
else num :=0;
end if;
else num :=0;
end if;
end loop;
END;

How about using a simple loop?
loop
v_return2 := function2(v_return);
exit when v_return2.count = 0;
v_return := function1(v_return2);
exit when v_return.count = 0;
end loop;

Related

Extracting entire JSON element sub elements

I have this bit of code here...
set serveroutput on;
DECLARE
v_response varchar(3000) := '{"content":{"stuff":{"cat":"meow","dog":"woof"}},"http_code":401,"response_code":"-1"}';
v_content varchar(3000);
BEGIN
select json_value(v_response, '$.content') into v_content from dual;
dbms_output.put_line('v_content: ' || v_content);
END;
I would expect the variable v_content to contain something along the lines of '{"stuff":{"cat":"meow","dog":"woof"}'. However it is returning nothing.
JSON_VALUE finds a specified scalar JSON value in JSON data and returns it as a SQL value.
select json_value('{"content":{"stuff":{"cat":"meow","dog":"woof"}},"http_code":401,"response_code":"-1"}', '$.content.stuff.cat') from dual
returned meow
Try this:
DECLARE
je JSON_ELEMENT_T;
jo JSON_OBJECT_T;
content JSON_OBJECT_T;
v_response varchar(3000) := '{"content":{"stuff":{"cat":"meow","dog":"woof"}},"http_code":401,"response_code":"-1"}';
BEGIN
je := JSON_ELEMENT_T.parse(v_response);
IF (je.is_Object) THEN
jo := treat(je AS JSON_OBJECT_T);
content := jo.get_Object('content');
END IF;
DBMS_OUTPUT.put_line(content.to_string);
END;

PL/SQL: ORA-00932: inconsistent datatypes: expected NUMBER got USER_NAME.VARCHAR_ARRAY

The below is a function that I am creating to accept an array of varchar2 items and return the internal pk of that record which is a NUMBER for each record. I am struggling to get the syntax right to pass an array of type VARCHAR_ARRAY to the simple sql query in the cursor and return the variable of type NUMBER_ARRAY. the Error is on line 8,42 i.e FROM table_name WHERE column_name IN VARCHAR_ARRAY which was passed to the function. Please help me with this error as I am learning plsql.
create or replace TYPE VARCHAR_ARRAY AS VARRAY(1000000) OF VARCHAR2(1000);
/
create or replace TYPE NUMBER_ARRAY AS VARRAY(1000000) OF NUMBER;
/
create or replace Function GET_PRODUCT_ID_ARR(V_PRODUCT_NUM_ARR IN VARCHAR_ARRAY)
RETURN NUMBER_ARRAY
IS
product_id_list number_array := number_array();
CURSOR c1
IS
SELECT cat_map_id
FROM mn_cat_map WHERE product_num IN (V_PRODUCT_NUM_ARR) and catalog_type = 'INT';
v_output NUMBER;
BEGIN
OPEN c1;
LOOP
fetch c1 into product_id_list;
EXIT WHEN c1%notfound;
product_id_list.extend;
product_id_list(product_id_list.count) := v_output;
dbms_output.put_line('Product ('||v_output ||'):'||product_id_list(v_output));
END LOOP;
Close c1;
RETURN product_id_list;
END;
/
There is two issues:
You have to cast varray to table:
CURSOR c1
IS
SELECT cat_map_id
FROM mn_cat_map
WHERE product_num IN (select column_value from table(V_PRODUCT_NUM_ARR))
and catalog_type = 'INT';
Add bulk collect after fetch:
LOOP
fetch c1 bulk collect into product_id_list limit 100;
EXIT WHEN c1%notfound;
product_id_list.extend;
product_id_list(product_id_list.count) := v_output;
dbms_output.put_line('Product ('||v_output ||'):'||product_id_list(v_output));
END LOOP;
If you write limit 100, each loop will put 100 records in product_id_list. You can omit limit clause, in this case you will get all records in one fetch.
EDIT
How to see results:
declare
myarray varchar_array;
my_num_array number_array;
begin
myarray := varchar_array();
myarray.extend(2);
myarray(1) := '151043';
myarray(2) := '2895';
my_num_array := GET_PRODUCT_ID_ARR(myarray);
for i in 1 .. my_num_array.count loop
dbms_output.put_line(my_num_array(i));
end loop;
end;
/
What #William is said is quiet true. VARRAY(1000000) is not recommended. Inplace you can create a type of table. However if i follow what you have done, there seems some mistakes in your code. Please see below how you can do it.
Tables Preparation:
create table mn_cat_map(cat_map_id number,
product_num varchar2(1000),
catalog_type varchar2(10));
/
INSERT INTO T541682.MN_CAT_MAP (CAT_MAP_ID, PRODUCT_NUM, CATALOG_TYPE)
VALUES (10, 'A123', 'INT');
INSERT INTO T541682.MN_CAT_MAP (CAT_MAP_ID, PRODUCT_NUM, CATALOG_TYPE)
VALUES (2, 'B121', '2Wheer');
INSERT INTO T541682.MN_CAT_MAP (CAT_MAP_ID, PRODUCT_NUM, CATALOG_TYPE)
VALUES (3, 'C645', '4Wheer');
COMMIT;
create or replace TYPE VARCHAR_ARRAY AS VARRAY(1000000) OF VARCHAR2(1000);
/
create or replace TYPE NUMBER_ARRAY AS VARRAY(1000000) OF NUMBER;
/
Code: read explainatory comments inline
CREATE OR REPLACE FUNCTION GET_PRODUCT_ID_ARR (V_PRODUCT_NUM_ARR VARCHAR_ARRAY)
RETURN NUMBER_ARRAY
IS
product_id_list number_array := number_array ();
CURSOR c1(tbl_list VARCHAR_ARRAY)
IS
SELECT cat_map_id
FROM mn_cat_map
WHERE product_num in (select column_value from table(tbl_list)) ---Checking if the item exists in the table with passed collection
AND catalog_type = 'INT';
v_output NUMBER:= 0;
BEGIN
--not opening cursor and am not looking for processing any records.
--OPEN c1(V_PRODUCT_NUM_ARR);
--passing the input varray to the cursor.
for i in c1(V_PRODUCT_NUM_ARR)
loop
v_output:=v_output + 1;
product_id_list.extend;
product_id_list(product_id_list.COUNT):= i.cat_map_id;
DBMS_OUTPUT.put_line('Product (' || v_output || '):' ||product_id_list(product_id_list.COUNT));
end loop;
RETURN product_id_list;
END;
/
Execution:
SQL> select GET_PRODUCT_ID_ARR(VARCHAR_ARRAY('A123','B121','C645')) COl1 from dual;
COL1
--------------------------------------------------------------------------------
NUMBER_ARRAY(10)
Product (1):10

Call by result Example

Is there any proper example for explaining call-by-result ? (not pseudocode)
I have learned that ALGOL 68, Ada could use this way,
but I cannot find any clear example of Call-by-Result.
I just made by myself.
pseudocode
begin
integer n;
procedure p(k: integer);
begin
n := n+1;
k := k+4;
print(n);
end;
n := 0;
p(n);
print(n);
end;
Implement using Ada Language
call.adb
with Gnat.Io; use Gnat.Io;
procedure call is
x : Integer;
Procedure NonSense (A: in out integer) is
begin
x := x + 1;
A := A + 4;
Put(x);
end NonSense;
begin
x := 0;
NonSense (x);
Put(" ");
Put(x);
New_Line;
end call;
Since Ada uses call-by-result way, result should be 1 4. (It could be checked by entering this code into online-Ada-compiler "http://www.tutorialspoint.com/compile_ada_online.php")
And, other result applied different passing parameter types should be...
call by value: 1 1
call by reference: 5 5
(compare > call by value-result: 1 4)

what does this code do exactly? and what is 'number(2)' function?

1.what exactly does this code do?
2.what is number(2)?
cursor c1 is
select employee_id, department_id, commission_pct from hr.employees;
emprec c1%rowtype;
v_hike number(2);
begin
open c1;
loop
fetch c1 into emprec;
exit when c1%notfound;
if emprec.department_id = 40 then v_hike := 10;
elsif emprec.department_id = 70 then v_hike := 15;
elsif emprec.commission_pct > 0.30 then v_hike := 5;
else v_hike := 10;
end if;
update employees set salary = salary + salary * v_hike/100
where employee_id = emprec.employee_id;
end loop;
end;
It's oracle cursor definition.. What exactly is that piece of sql doing is so hard to know how hard you can read it.
In first row you can see select which works with many set of rows.. Then you have define local variable. v_hike. In loop it's doing some expresions like count v_hike and then it's set new salary to employer
number(2) is incorrect write, it should be: number(p,s) where p-s digits before the decimal and s digits after the decimal..
what exactly does this code do?
First of all, in Oracle PL/SQL, it is syntactically incorrect since you have missed the DECLARE keyword in your PL/SQL anonymous block. You will get a compilation error.
Let me explain step by step :
cursor c1 is
select employee_id, department_id, commission_pct from hr.employees;
emprec c1%rowtype;
It is an explicit cursor, it is a work area to store the processing information of the select query. And emprec is a collection type which will hold the resultset when you issue the FETCH statement.
v_hike number(2);
This is a variable declared of NUMBER data type. NUMBER(2) means it can hold a number value with PRECISION 2.
begin
open c1;
loop
fetch c1 into emprec;
exit when c1%notfound;
if emprec.department_id = 40 then v_hike := 10;
elsif emprec.department_id = 70 then v_hike := 15;
elsif emprec.commission_pct > 0.30 then v_hike := 5;
else v_hike := 10;
end if;
update employees set salary = salary + salary * v_hike/100
where employee_id = emprec.employee_id;
end loop;
end;
Next steps are,
a. Open the cursor
b. for each row in the cursor, loop through and prepare the
collection in emprec
c. When there are no records to fetch from cursor then exit
d. Assign a number value to the v_hike variable based on the IF-ELSE
construct.
e. execute the UPDATE statement.
f. Come out of loop.
g. Scope of block ends with END keyword.

Postgres Function End Loop and return Error

I have tried to create this function but the system is returning a "LOOP error" and I don't know how to return 3 variables at the same time. I've tried hard to figure this out but I didn't find an answer anywhere.
CREATE OR REPLACE FUNCTION conta_relatos(fator_normativo integer, fator_determinativo integer)
RETURNS integer AS
$BODY$
DECLARE
vinculos_encontrados RECORD;
rel_pri INT;
rel_sec INT;
rel_ref INT;
no_item INT;
tipo_relato TEXT;
BEGIN
rel_pri := 0;
rel_sec := 0;
rel_ref := 0;
FOR vinculos_encontrados IN SELECT * FROM "Vinculos" WHERE ("Vinculos"."Fator_Normativo" = Fator_Normativo AND "Vinculos"."Fator_Determinativo" = Fator_Determinativo) LOOP
no_item := vinculos_encontrados."Item";
SELECT "Fontes"."Tipo_Relato" INTO tipo_relato FROM "Fontes" WHERE "Fontes"."ID" = no_item;
--IF tipo_relato = "1 - Relato Primário" THEN
rel_pri := rel_pri + 1;
--ELSE IF tipo_relato = "2 - Relato Secundário" THEN
rel_sec := rel_sec + 1;
--ELSE IF tipo_relato = "3 - Relato Referencial" THEN
rel_ref := rel_ref + 1;
--END IF;
END LOOP;
RETURN rel_pri, rel_sec, rel_ref;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
Use OUT parameters to return a single row with multiple columns. The RETURN type is optional in this case, I quote the manual here:
When there are OUT or INOUT parameters, the RETURNS clause can be omitted.
CREATE OR REPLACE FUNCTION conta_relatos(
_fator_normativo integer
,_fator_determinativo integer
,OUT rel_pri integer
,OUT rel_sec integer
,OUT rel_ref integer
) AS
$func$
DECLARE
tipo_relato text;
BEGIN
rel_pri := 0;
rel_sec := 0;
rel_ref := 0;
FOR tipo_relato IN
SELECT f."Tipo_Relato"
FROM "Vinculos" v
JOIN "Fontes" f ON f."ID" = v."Item"
WHERE v."Fator_Normativo" = _fator_normativo
AND v."Fator_Determinativo" = _fator_determinativo
LOOP
CASE tipo_relato
WHEN '1 - Relato Primário' THEN
rel_pri := rel_pri + 1;
WHEN '2 - Relato Secundário' THEN
rel_sec := rel_sec + 1;
WHEN '3 - Relato Referencial' THEN
rel_ref := rel_ref + 1;
END CASE;
END LOOP;
-- No RETURN needed, OUT parameters are returned automatically.
END
$func$ LANGUAGE plpgsql;
Call:
SELECT * FROM conta_relatos(1,2);
I also largely simplified your function. Among others:
Use "Simple CASE" for your assignments.
Simplify two queries into one with a join.
The whole function could easily be rewritten as a single SQL statement.
To return multiple values at the same time, you'll want to specify OUT parameters and change the return type of the function to record. See the documentation here. Make sure to call the function with SELECT * to get the parameters back as 3 columns.
Please update your question to include the error you are getting, and if I can help I will update this answer to address it.