Pass Multivalue in WHERE IN ORACLE [duplicate] - oracle

This question already has answers here:
PL/SQL - comma separated list within IN CLAUSE
(4 answers)
Closed 4 years ago.
I need you help to pass a multivalue to a stored procedure in Oracle,
The values are created dynamically.
Basically I'm sending the values from .NET in a simple "string" and Oracle receives it as varchar2:
Stored Procedure
create or replace procedure sp_text_in
(text varchar2)
AS
CURSOR texts
IS
SELECT text FROM t_text where key_text in (text)
;
BEGIN
FOR reg IN texts LOOP
dbms_output.put_line(reg.text);
END LOOP;
end sp_text_in;
Example: the values can be:
select * from t_text where key_text in (197,198,196);
OR simply one value
select * from t_text where key_text in (197);

Ideal option is as per the link shared by #anonyXmous. Another sub optimal option is using dynamic SQL. But this could allow SQL injection. Dynamic SQL solution below.
create or replace procedure SP_TEXT_IN (TEXT varchar2)
as
type TEXTSTABTYP is table of varchar2(1000);
TEXTSTAB TEXTSTABTYP := TEXTSTABTYP();
begin
execute immediate 'select TEXT from T_TEXT where KEY_TEXT in ('||TEXT||')'
bulk collect into TEXTSTAB;
for IDX in TEXTSTAB.first..TEXTSTAB.last
loop
dbms_output.put_line(TEXTSTAB(IDX));
end loop;
end sp_text_in;

Related

LISTAGG 4000 Character Limit - Result of string concatenation is too long [duplicate]

This question already has answers here:
Oracle - convert column values to comma separated values as CLOB without using XMLAGG
(1 answer)
ORA-64451: Conversion of special character to escaped character failed
(1 answer)
Closed 8 months ago.
select t.name, listagg(t.text)
from user_source t
group by t.name;
I am trying to execute the code above but since varchar2 is limited by 4000 chars it throws error. I tried to convert listagg to xml but I could not solve the
ORA-64451: Conversion of special character to escaped character failed.
error. I also tried the answers from other posts from various websites including stackoverflow.
I do not want to truncate the string, also I can't change MAX_STRING_SIZE parameter.
This example below throws ORA-64451 as well. I tried but could not solve the problem.
select rtrim(
xmlagg(
xmlelement(e, to_clob(t.TEXT), '; ').extract('//text()')
).GetClobVal(),
',')
from user_source t;
The best solution I know is posted somewhere in the Internet... You could probably just google for it. It basically consist of few steps:
Creating a collection type to store each text value to concatenate
create or replace type string_array_t as table of VARCHAR2(4000);
Creating a PL/SQL function which takes string_array_t as parameter and returns concatenated text as CLOB:
create or replace function
string_array2clob(
p_string_array string_array_t
,p_delimiter varchar2 default ','
) RETURN CLOB IS
v_string CLOB;
BEGIN
-- inside is a loop over p_string_array to concatenate all elements
--
-- below is just a draft because in real you should use a while loop
-- to handle sparse collection and you should put some checks to handle not initialized collection
-- and other important cases
-- furthermore it's better to create additional varchar2 variable as a buffer
-- and convert that buffer to clob when it's full for a better performance
for indx in p_string_array.first..p_string_array.last loop
v_string := v_string || to_clob(p_string_array(indx) || p_delimiter);
end loop;
RETURN substr(v_string, 1, nvl(length(v_string),0) - nvl(length(p_delimiter),0));
END string_array2clob;
/
Aggregate query as usual but using cast and collect instead of listagg and at the end convert it to clob with function from step above:
select t.name, string_array2clob(cast(collect(t.text order by t.line) as string_array_t ), p_delimiter => chr(10)) as text
from user_source t
group by t.name;
If your query is not just an example of concept and really you're trying to get a source of some object in database, then you should read about dbms_metadata.get_ddl function. It's made for it.

ORACLE - Selecting Parameters for calling Procedure from Table

Is it possible to select the parameters for calling a procedure from the select statement?
EXECUTE PROCEDURE_NAME(para1,para2,para3,para4);
commit;
Is it possible to select para1,para2,para3,para4 from a select query?
EXECUTE PROCEDURE_NAME((SELECT PARA1,PARA2,PARA3,PARA4 FROM TABLEA))
COMMIT;
I do not have access to modify the procedure.
As a slight variation on what #vc74 suggested, you could just replace your EXECUTE command (which, assuming this is SQL*Plus or SQL Developer anyway, is just a wrapper for an anonymous block anyway) with an explicit anonymous block:
begin
for r in (SELECT PARA1,PARA2,PARA3,PARA4 FROM TABLEA) loop
PROCEDURE_NAME(r.PARA1,r.PARA2,r.PARA3,r.PARA4);
end loop;
end;
/
(I've left the bits from your original call uppercase and the new bits lower case mostly to distinguish them.)
Using a loop just means you don't need to declare local variables and select into those. It would also allow you to process multiple rows from the table, though I see form a comment you only expect one row. However, the flip side of that is it won't complain if there are no rows, or if there is more than one row, as the variable approach would do.
You could also use a record type to avoid declaring all the parameters separately:
declare
l_row tablea%rowtype;
begin
SELECT * into l_row FROM TABLEA;
PROCEDURE_NAME(l_row.PARA1,l_row.PARA2,l_row.PARA3,l_row.PARA4);
end;
/
This now does expect exactly one row to be found in the table.
You can call the functions in sql. So if you are able to create a function in your schema then you can do the following:
create a function function_name in your schema that calls the procedure procedure_name and returns some dummy result
use this function in sql query: select function_name(para1,para2,para3,para4) from tablea
example of function:
create or replace function function_name(
p1 varchar2,
p2 varchra2,
p3 varchar2,
p4 varchar2
) return number
is
begin
procedure_name(p1,p2,p3,p4); -- here you execute the procedure
return null;
end;

Function returning REF CURSOR [duplicate]

This question already has answers here:
fetch from function returning a ref cursor to record
(3 answers)
Closed 7 years ago.
I have package like this:
CREATE OR REPLACE PACKAGE product_package AS
TYPE t_ref_cursor to IS REF CURSOR;
FUNCTION get_products_ref_cursor RETURN t_ref_cursor;
END product_package;
CREATE OR REPLACE PACKAGE BODY product_package AS
FUNCTION get_products_ref_cursor is RETURN t_ref_cursor IS
products_ref_cursor t_ref_cursor;
BEGIN
OPEN products_ref_cursor FOR
SELECT product_id, name, price FROM Products;
RETURN products_ref_cursor;
END get_products_ref_cursor;
END product_package;
My question is, how can I use function get_products_ref_cursor (ref cursor) to get list of products?
declare
type rec is record(produc_id number, name varchar2(x), price number);
type l_rec is table of rec;
v_l_rec l_rec;
v_cursor product_package.t_ref_cursor;
begin
v_cursor := product_package.get_products_ref_cursor;
fetch v_cursor bulk collect into v_l_rec;
-- in v_l_rec is list collection of products.
close v_cursor;
end;
Code wasn't tested.
It depends on the language or tool from which you are calling the function. If you are calling from SQL*Plus, you can just
print <variable_name>
where is the name of the PL/SQL bind variable to which you returned the function's results.
If you are in PL/SQL, you need to write a loop where you fetch... exit when %NOTFOUND... etc. There are a million examples, including the PL/SQL Users Guide.
If you are in Java, you cast the cursor object as a ResultSet and fetch its results in a loop.
Other languages will have other ways, but they mostly all entail looping through the cursor and fetching the results.
So... it depends on the caller's language.

How can fill a variable of my own created data type within Oracle PL/SQL?

In Oracle I've created a data type:
TABLE of VARCHAR2(200)
I want to have a variable of this type within a Stored Procedure (defined locally, not as an actual table in the DB) and fill it with data.
Some online samples show how I'd use my type if it was filled and passed as a parameter to the stored procedure:
SELECT column_value currVal FROM table(pMyPassedParameter)
However what I want is to fill it during the PL/SQL code itself, with INSERT statements.
Anyone knows the syntax of this?
EDIT: I should have clarified: my source data is entered as a VARCHAR2 parameter passed to the stored procedure: a separator (like comma) delimited string. I'm already iterating through the delimited string to get every separate value - I would like to INSERT each one into my type so I can treat it as a TABLE for the rest of the logic.
"I want is to fill it during the PL/SQL
code itself, with INSERT statements"
It's like populating any other PL/SQL variable: we have to use INTO. Only because we're populating multiple rows we need to use the BULK COLLECT syntax.
declare
l_array your_nested_table_type;
begin
select col1
bulk collect into l_array
from t72;
end;
/
If the result set returns a lot of records it is a good idea to use the LIMIT clause inside a loop. This is because PL/SQL collections - just like every other PL/SQL variable - are held in session memory. So we don't want the array to get too big, otherwise it might blow the PGA. Find out more.
edit
"I edited the question to clarify
specifically what I want"
sigh Tokenizing a string is an altogether different issue. I have previously posted solutions in two SO threads. If you're using 9i or earlier use this approach. Otherwise use this regex solution (actually this splits the string into numeric tokens, but it is easy enough to convert to characters).
edit 2
"I only want to be able to use the
type "internally" (within the Stored
Procedure) by adding values to it. Is
this something I can do with the first
link?"
Sure. Why not?
SQL> declare
2 local_array tok_tbl;
3 begin
4 local_array := parser.my_parse('Keith Pellig,Peter Wakeman,Ted Bentley,Eleanor Stevens');
5 local_array.extend();
6 local_array(5) := 'Reese Verrick';
7 for i in local_array.first()..local_array.last()
8 loop
9 dbms_output.put_line(local_array(i));
10 end loop;
11 end;
12 /
Keith Pellig
Peter Wakeman
Ted Bentley
Eleanor Stevens
Reese Verrick
PL/SQL procedure successfully completed.
SQL>
Here I have re-used my SQL type, but it would work just as well if TOK_TBL were declared in the PL/SQL package instead.
you don't mention if the type you created is a SQL type or a PL/SQL type. They are used similarly in Pl/SQL so I will assume you created a SQL type with a command like this:
SQL> CREATE TYPE tab_varchar IS TABLE of VARCHAR2(200);
2 /
Type created
This is a nested-table. Find out how to manipulate collections in PL/SQL it in the documentation, for example:
SQL> DECLARE
2 lt tab_varchar;
3 BEGIN
4 /* initialization */
5 lt := tab_varchar('a', 'b', 'c');
6 /* adding elements */
7 lt.extend(1);
8 lt(4) := 'd';
9 FOR i IN lt.FIRST .. lt.LAST LOOP
10 dbms_output.put_line('lt(' || i || ')=' || lt(i));
11 END LOOP;
12 END;
13 /
lt(1)=a
lt(2)=b
lt(3)=c
lt(4)=d

How do I return the rows from an Oracle Stored Procedure using SELECT?

I have a stored procedure which returns a ref cursor as follows:
CREATE OR REPLACE PROCEDURE AIRS.GET_LAB_REPORT (ReportCurTyp OUT sys_refcursor)
AS
v_report_cursor sys_refcursor;
report_record v_lab_report%ROWTYPE;
l_sql VARCHAR2 (2000);
BEGIN
l_sql := 'SELECT * FROM V_LAB_REPORT';
OPEN v_report_cursor FOR l_sql;
LOOP
FETCH v_report_cursor INTO report_record;
EXIT WHEN v_report_cursor%NOTFOUND;
END LOOP;
CLOSE v_report_cursor;
END;
I want to use the output from this stored procedure in another select statement like:
SELECT * FROM GET_LAB_REPORT()
but I can't seem to get my head around the syntax.
Any ideas?
Whenever I've had to do this; I've used the Oracle TYPE and CAST features.
Something like:
SELECT *
FROM TABLE(CAST(F$get_Cassette_Tracking('8029241') AS cass_tracking_tab_type))
You need to setup the TYPE and all the columns you need and have them use:
pipe ROW(out_obj)
to capture your data. There are many ways to do this and if I can dig out a better example I will but this might give you an idea.
See this SO for a working example: Oracle Parameters with IN statement?

Resources