I have a PL/SQL package that contains a procedure that I need to use to validate my result.
An example of this can look like this:
create or replace PACKAGE MY_TEST
IS
PROCEDURE validate_my_value (p_input_value INT,
p_valid OUT INT);
END;
create or replace PACKAGE BODY MY_TEST
IS
PROCEDURE validate_my_value (p_input_value INT,
p_valid OUT INT)
IS
BEGIN
p_valid := 0;
IF MOD(p_input_value, 2) = 0 THEN
p_valid := 1;
END IF;
END;
END;
I would like to call this procedure a number of times, and return the valid results in a sys_refcursor from a function on another PL/SQL package.
I have an example where I collect the valid results in an array, but in the end I cannot seem to get the output format quite right.
Example:
create or replace PACKAGE MY_TEST_CLIENT
IS
FUNCTION get_validated_values (p_input_begin INT,
p_input_end INT)
RETURN sys_refcursor;
END;
create or replace PACKAGE BODY MY_TEST_CLIENT
IS
TYPE t_num_array IS TABLE OF INTEGER;
FUNCTION get_validated_values (p_input_begin INT,
p_input_end INT)
RETURN sys_refcursor
IS
l_current_value INT;
l_valid INT;
l_result_cursor sys_refcursor;
l_result t_num_array := new t_num_array();
l_count INT := 1;
BEGIN
l_valid := 0;
l_current_value := p_input_begin;
LOOP
MY_TEST.VALIDATE_MY_VALUE(l_current_value, l_valid);
IF l_valid = 1 THEN
l_result.extend();
l_result(l_result.count) := l_current_value;
END IF;
EXIT WHEN l_current_value >= p_input_end;
l_current_value := l_current_value 1;
END LOOP;
IF l_result.count() = 0 THEN
return l_result_cursor;
END IF;
-- TODO convert l_result into l_result_cursor
open l_result_cursor for
-- SELECT * FROM TABLE(l_result); -- This does not work. ORA-22905 and ORA-00642
select 1 from dual; -- Dummy value
return l_result_cursor;
END;
END;
And finally I would like to be able to call the method with something like this:
SELECT MY_TEST_CLIENT.get_validated_values(1,10) from DUAL;
So, based on the example here, the validator should only result in equal numbers. E.g.: 2, 4, 6, 8 and 10.
I tried something similar to Oracle: How to populate/insert row to a Ref Cursor? but cannot get the output cursor to accept a result.
I also tried to loop through the result and create a single SQL statement (select value from dual union ...). However, I had no luck executing the generated SQL statement in a way that left me with a result that could be returned by the sys_refcursor.
Any pointers on how to outputting the result would be appreciated.
CodePudding user response:
On order to use SELECT * FROM TABLE(l_result)
you must create the type as database object, i.e.
CREATE TYPE t_num_array IS TABLE OF INTEGER;
instead of defining it inside the PL/SQL package.
NB, you can get the same result with this "one-liner":
open l_result_cursor for
with t as
(select rownum p_input_begin as r
from dual
connect by rownum <= p_input_end 1)
select r
from t
where mod(r,2)= 0;
CodePudding user response:
@Wernfried gave the clue to why I was having issues with my initial question, and adding an type to the database helped being able to make the SELET * FROM TABLE(l_result);
work.
create or replace TYPE t_num_array AS TABLE OF INTEGER;
However, the pipeline suggestion by @Justin actually made more sense in this case. So, with pipelined output, the solution may looks like this:
create or replace PACKAGE BODY MY_TEST_CLIENT2
IS
FUNCTION get_validated_values (p_input_begin INT,
p_input_end INT)
return t_num_array pipelined
IS
l_current_value INT;
l_valid INT;
BEGIN
l_valid := 0;
l_current_value := p_input_begin;
LOOP
MY_TEST.VALIDATE_MY_VALUE(l_current_value, l_valid);
IF l_valid = 1 THEN
pipe row (l_current_value);
END IF;
EXIT WHEN l_current_value >= p_input_end;
l_current_value := l_current_value 1;
END LOOP;
RETURN;
END;
END;
And calling it will do this:
SELECT MY_TEST_CLIENT2.get_validated_values(1,10) from DUAL;
-- TT.T_INTEGER_ARRAY(2, 4, 6, 8, 10)
Or using the suggesting by @Justing
SELECT * from table(MY_TEST_CLIENT2.get_validated_values(1,10));
/*
2
4
6
8
10
*/