Convert stored proc to table to be able to use in select statement - plsql

I have to use existing stored procedure which returns REF CURSOR. I need to insert that resultset into a temporary table.
Spec of procedure is:
TYPE cur IS REF CURSOR;
PROCEDURE get(p_one NUMBER ,p_two OUT cur);
How can I insert the resultset of this procedure into a table.

I just re-read the title of your question. Do you actually need to be able to select from a procedure?
If so, this can be achieved by using pipelined functions.
The process for this is:
Create an object type to represent the record-type you require.
Create a nested table type of the object.
Create a pipelined function which returns the nest table.
You can then select from this function.
This example should get you on your way:
create or replace type to_test as object (
val1 varchar2(32),
val2 varchar2(32)
);
create or replace type tt_test as table of to_test;
create or replace function demo_pipe return tt_test pipelined
is
v_test to_test;
begin
for rec in (select * from user_tables) loop
v_test := to_test(rec.table_name, rec.tablespace_name);
pipe row (v_test);
end loop;
end;
/
select * from table(demo_pipe);

Related

Procedure created with compilation errors. payment_count(l_p_count); *

Create a procedure named 'payment_count' which accepts one output parameter p_count with number as its data type. This procedure should print the count of successful payments (response_msg as 'Successful') with alias name as 'successful_payment_count'.
Hints: Procedure name : payment_count
Output parameter : p_count
Table used : payment_authorization
Function used : count
create or replace procedure payment_count(p_count output number)
as
begin
select count(response_msg='Successful') into successful_payment_count from payment_authorization;
return successful_payment_count;
end;
/
schema payment_authorization
Is this a task in an exam?
Sounds so... anyway:
You have to change keyword output to OUT, change the COUNT(response_msg='Successful') to COUNT(*) and add response_msg='Successful' to the where clause of the query.
create or replace procedure payment_count(p_count out number)
as
begin
select count(response_msg) as successful_payment_count
into p_count
from payment_authorization
where response_msg = 'Successful';
end;
/

how to use collection type in PLSQL, while receiving multiple value from front end java page?

Actually my requirement is,am having 3 tables so i need to create type for each table or consolidate type to all table. but in java developer have to send the multiple parameter to my Procedure, so how to get the multiple values in single type and insert it into table??
Object type
CREATE OR REPLACE TYPE "POL_QUAT_TYPE"
IS OBJECT (V_POLICY_NO VARCHAR2 (30),
V_FOREIGN_POLICY VARCHAR2 (1));
tabletype
CREATE OR REPLACE TYPE POL_QUAT_table IS TABLE OF POL_QUAT_TYPE
Sample procedure
CREATE OR REPLACE PROCEDURE TEST1 (A POL_QUAT_TYPE) IS
B VARCHAR2(100);
C VARCHAR2(100);
BEGIN
B:=A(1);
C:=A(1);
INSERT INTO TEST ( PART, B )
VALUES (B,C);
COMMIT;
END;
Call this procedure
begin
test1('a','b');
end;
I want to know how get the value (a,b) though procedure from collection type.
Ok, you can insert the contents of an array of objects into the table like so:
CREATE OR REPLACE TYPE "POL_QUAT_TYPE"
IS OBJECT (V_POLICY_NO VARCHAR2 (30),
V_FOREIGN_POLICY VARCHAR2 (1));
/
CREATE OR REPLACE TYPE POL_QUAT_table IS TABLE OF POL_QUAT_TYPE;
/
CREATE OR REPLACE PROCEDURE TEST1 (p_a in POL_QUAT_table)
as
BEGIN
INSERT INTO TEST (PART, B)
select t.v_policy_no,
t.v_foreign_policy
from table(p_a) t;
COMMIT;
END;
/
I've created a test case to demonstrate that it works over on Oracle LiveSQL.
This means you can insert all the content of the array in one go without having to loop through the array and insert one record at a time, so it should be much more performant.

PL SQL: How to populate a cursor in loop

I have a scenario to implement where in we will have an SP with two parameters
1) In parameter of array of Varchar2
2) Cursor -- Out parameter
We have populate the cursor only for each Value passed in array and this opened/populated cursor will be used by Java. But what i have found till now is, if we have to process an array then it should have to be done using loop.
For ex:
Open Cursor_Name
For
For index In Arrar_Parameter.FIRST .. Arrar_Parameter.LAST
LOOP
SELECT * FROM EMP WHERE EmpId = Arrar_Parameter[i] -------> This needs to be looped and not sure if this will work
END LOOP
Can we have some thing like this
Open Cursor_Name
For
SELECT * FROM EMP WHERE EmpId IN (Arrar_Parameter values) ------> To fetch/put all the array values at once without loop.
Kindly suggest hot to populate cursor in this scenario
Assuming your array parameter is a schema-level varray or nested table, you can use a table collection expression:
The table_collection_expression lets you inform Oracle that the value of collection_expression should be treated as a table for purposes of query and DML operations. The collection_expression can be a subquery, a column, a function, or a collection constructor. Regardless of its form, it must return a collection value—that is, a value whose type is nested table or varray. This process of extracting the elements of a collection is called collection unnesting.
This uses a built-in varray type but you can substitute your own:
create procedure procedure_name (
array_parameter sys.odcivarchar2list, cursor_name out sys_refcursor
) as
begin
open cursor_name for
select e.*
from table (array_parameter) a
join emp e on e.empid = a.column_value;
end;
/
You can also use in if you prefer:
create procedure procedure_name (
array_parameter sys.odcivarchar2list, cursor_name out sys_refcursor
) as
begin
open cursor_name for
select *
from emp
where empid in (select column_value from table (array_parameter));
end;
/
If it is a nested table you can also use the member of syntax:
create type my_varchar2_table as table of varchar2(30);
/
create procedure procedure_name (
array_parameter my_varchar2_table, cursor_name out sys_refcursor
) as
begin
open cursor_name for
select *
from emp
where empid member of array_parameter;
end;
/

A generic procedure that can execute any procedure/function

input
Package name (IN)
procedure name (or function name) (IN)
A table indexed by integer, it will contain values that will be used to execute the procedure (IN/OUT).
E.g
let's assume that we want to execute the procedure below
utils.get_emp_num(emp_name IN VARCHAR
emp_last_name IN VARCHAR
emp_num OUT NUMBER
result OUT VARCHAR);
The procedure that we will create will have as inputs:
package_name = utils
procedure_name = get_emp_num
table = T[1] -> name
T[2] -> lastname
T[3] -> 0 (any value)
T[4] -> N (any value)
run_procedure(package_name,
procedure_name,
table)
The main procedure should return the same table that has been set in the input, but with the execution result of the procedure
table = T[1] -> name
T[2] -> lastname
T[3] -> 78734 (new value)
T[4] -> F (new value)
any thought ?
You can achieve it with EXECUTE IMMEDIATE. Basically, you build a SQL statement of the following form:
sql := 'BEGIN utils.get_emp_num(:1, :2, :3, :4); END;';
Then you execute it:
EXECUTE IMMEDIATE sql USING t(1), t(2), OUT t(3), OUT t(4);
Now here comes the tricky part: For each number of parameters and IN/OUT combinations you need a separate EXECUTE IMMEDIATE statement. And to figure out the number of parameters and their direction, you need to query the ALL_ARGUMENTS table first.
You might be able to simplify it by passing the whole table as a bind argument instead of a separate bind argument for each table element. But I haven't quite figured out how you would do that.
And the next thing you should consider: the elements of the table T your using will have a type: VARCHAR, NUMBER etc. So the current mixture where you have both numbers and strings won't work.
BTW: Why do you want such a dynamic call mechanism anyway?
Get from the all_arguments table the argument_name, data_type, in_out, and the position
Build the PLSQL block
DECLARE
loop over argument_name and create the declare section
argument_name data_type if in_out <> OUT then := VALUE OF THE INPUT otherwise NULL
BEGIN
--In the case of function create an additional argument
function_var:= package_name.procedure_name( loop over argument_name);
--use a table of any_data, declare it as global in the package
if function then
package_name.ad_table.EXTEND;
package_name.ad_table(package_name.ad_table.LAST):= function_var;
end if
--loop over argument_name IF IN_OUT <> IN
package_name.ad_table.EXTEND;
package_name.ad_table(package_name.ad_table.LAST):=
if data_type = VARCHAR2 then := ConvertVarchar2(argument_name)
else if NUMBER then ConvertNumber
else if DATE then ConvertDate
...
END;
The result is stored in the table.
To get value use Access* functions

Select from PLSQL Associative array?

Is it possible to use SELECT FROM when using an associative array? I'm passing an array to a stored procedure through a .NET application, and I wanna be able to use that array as a condition when selecting from another table. Lets say I'm passing an array of IDs to the procedure, I wanna be able to do this:
select * from table1 where userID in (select column_value from array)
The type for the array is defined in the package:
type id_array is type of number index by pls_integer
Yes, it is possible, by wrapping the array with a pipelined function. Here's a good primer on pipelined functions:
http://www.oracle-developer.net/display.php?id=429
UPDATE: Oracle 12c now supports querying associative arrays using the TABLE operator, as long as the type is declared in a package spec: https://galobalda.wordpress.com/2014/08/02/new-in-oracle-12c-querying-an-associative-array-in-plsql-programs/
e.g.
select * from table1
where userID in (select column_value from table(array));
No, you can't select from PL/SQL arrays, since you use SQL in select from statements, though you can use DB defined Nested Tables types in SQL. This short article can help you get started.
Take a look a this simple synthetic exmple:
> create type temp_t as table of int;/
Type created.
> select 'test' from dual where 1 in (select * from table(temp_t(1,2,3)));
'TES
----
test
An example using PLSQL (to select from a nested table):
create type temp_r as OBJECT(
temp_varchar2 varchar2(100),
temp_number number(20)
);
/
create type temp_t as TABLE of temp_r;
/
set serveroutput on size 1000000
/
-- PLSQL starts here
declare
temp_rec temp_r := temp_r(null, null); -- empty constructor to initialize object
temp_table temp_t := temp_t(); -- empty constructor to initialize object
lv_ref_cursor SYS_REFCURSOR;
lv_temp_varchar2 varchar(100);
lv_temp_number number(20);
begin
temp_rec.temp_varchar2 := 'first';
temp_rec.temp_number := 1;
temp_table.extend;
temp_table(1) := temp_rec;
temp_table.extend;
temp_table(2) := temp_r('second', 2);
OPEN lv_ref_cursor FOR
SELECT temp_varchar2, temp_number
FROM table(temp_table)
where temp_number = 1;
fetch lv_ref_cursor into lv_temp_varchar2, lv_temp_number;
close lv_ref_cursor;
dbms_output.put_line('returns: ' || lv_temp_varchar2 || ', ' || lv_temp_number);
end;
/

Resources