Oracle parameter and IN clause in SSRS(RDL) reports - c#

Before marked as duplicate, I have read the following:
Oracle "IN clause" from parameter
Parameterize an SQL IN clause
problem using Oracle parameters in SELECT IN
Supposed I have this query on my DataSource in my .rdl report published in our report server:
SELECT ...
FROM ...
WHERE c.cluster_cd IN (:paramClusterCD)
Report Builder 2.0 automatically recognized a parameter as #paramClusterCD. On my wpf project, I have to create a parameter with multiple values like this:
var arrCluster = (lbCluster.SelectedItems.Cast<CLUSTER_MSTR>().ToList()).Select(x => x.CLUSTER_CD).ToArray();
string strCluster = string.Join(",", arrCluster); // result is "1,2,3"
Now whenever I run(pass the parameter in the report viewer), I have this error:
ORA-01722: invalid number
Workaround from the previous post won't work since this is a SSRS report.

It's not going to work this way, because Oracle won't recognize that you're actually trying to pass in a list of possible values.
What you want is a query like
select * from t where x in (1,2,3)
but what your code does is
select * from t where x = '1,2,3'
As x is numeric, Oracle tries to cast '1,2,3' into a number - and fails...
Please refer to this excellent thread at AskTom for correct solutions (and a sermon about the importance of bind variables).
Update: Tom's first answer already contains everything you need, but it used the now obsolete THE keyword instead of TABLE. So here are the steps that should work for you:
first create a type for a collection of numbers
create or replace type TableOfNumber as table of number;
then create a function that splits your string and returns your newly created collection
create or replace function in_list( p_string in varchar2 ) return TableOfNumber as
l_string long default p_string || ',';
l_data TableOfNumber := TableOfNumber();
n number;
begin
loop
exit when l_string is null;
n := instr( l_string, ',' );
l_data.extend;
l_data(l_data.count) := to_number( substr( l_string, 1, n-1 ) );
l_string := substr( l_string, n+1 );
end loop;
return l_data;
end;
Now you can use this function in a query:
SELECT ...
FROM ...
WHERE c.cluster_cd IN
(select * from TABLE (select cast(in_list(:paramClusterCD) as mytableType) from dual))

Kindly try the below if you can ensure that the parameters passed is a number and if c.cluster_cd is a number column
SELECT ...
FROM ...
WHERE to_char(c.cluster_cd) IN ((:paramClusterCD));

Related

Retreiving a subset of data from an Oracle database

I have an Oracle 19c database that I am trying to pull data from using a package procedure. It is working, but I am new to Oracle, previously very experienced in Microsoft SQL Server. The C# code I have below works and calls my stored procedure successfully. However, the stored procedure returns over one million rows. I do not want to have a DataSet filled with over a million rows because obviously this is very slow. I would like to return is a subset, like offset X rows and take N rows. Basically I want to do something like this:
SELECT * FROM STORED_PROCEDURE OFFSET 50 ROWS FETCH NEXT 50 ROWS ONLY
But I want to do it using my package procedure. Here is my C# code:
public async Task<List<DbModels.DocumentWipList>> GetWipDocumentsAsync(string sort = "limited_dodiss ASC")
{
using (var connection = new OracleConnection(_configuration.GetConnectionString("OracleDev")))
{
using (var command = connection.CreateCommand())
{
connection.Open();
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "PKG_GET_COMPONENT_DETAIL.pr_get_wip_comp_list_sorted";
command.Parameters.Add("arg_sort", OracleDbType.Varchar2).Value = sort;
command.Parameters.Add("io_cursor", OracleDbType.RefCursor).Direction = ParameterDirection.Output;
using (var da = new OracleDataAdapter())
{
da.SelectCommand = command;
var dt = new DataTable();
await Task.Run(() => da.Fill(dt));
return MapDocumentWipList(dt);
}
}
}
}
It should be noted that I cannot modify the package procedure. I am hoping there is an easy way to do this, perhaps by somehow wrapping the package procedure as a subquery for a SELECT query.
In Oracle, a cursor is effectively a pointer to a memory address on the database server where the database stores the query the cursor executes and the current execution state of the cursor (a cursor never stores the result set waiting to be read, that is effectively generated on the fly as each row is read). You can read from a cursor once but you cannot change the cursor or rewind it.
I would like to return is a subset, like offset X rows and take N rows.
Don't use await Task.Run(() => da.Fill(dt));. Instead, read and ignore X rows for the cursor and then read and store N rows.
However, it would be better to change the procedure to allow pagination.
What about filtering? One of the columns that comes back is OWNER_NAME. What if I wanted to pull just the rows WHERE OWNER_NAME LIKE 'R%' or something like that?
It is impossible to modify a cursor, if you have to read it then you will need to read ALL the rows for the cursor and discard the rows that do not match your condition. So again, don't use await Task.Run(() => da.Fill(dt));, which would load all the rows into memory, instead read the rows one-by-one and only keep the ones you want in memory and forget the rest.
You can write a second procedure in PL/SQL to wrap around the cursor or you can do the processing in a third-party application like C# but you will need to read the cursor. All that changes between doing it in PL/SQL or C# is whether the processing occurs on the database server or on the third-party application server.
For example, if you have the table:
CREATE TABLE table_name (a, b, c) AS
SELECT LEVEL, CHR(64 + LEVEL), DATE '1970-01-01' + LEVEL - 1
FROM DUAL
CONNECT BY LEVEL <= 10;
And an existing procedure (that cannot be changed):
CREATE PROCEDURE get_cursor (
o_cursor OUT SYS_REFCURSOR
)
IS
BEGIN
OPEN o_cursor FOR
SELECT * FROM table_name;
END;
/
Then you can create the types:
CREATE TYPE table_name_type IS OBJECT(
a NUMBER,
b VARCHAR2(1),
c DATE
);
CREATE TYPE table_name_array IS TABLE OF table_name_type;
Which allows you to create a pipelined function:
CREATE FUNCTION wrap_cursor_fn (
i_cursor IN SYS_REFCURSOR
) RETURN table_name_array PIPELINED
IS
v_a table_name.a%TYPE;
v_b table_name.b%TYPE;
v_c table_name.c%TYPE;
BEGIN
LOOP
FETCH i_cursor INTO v_a, v_b, v_c;
EXIT WHEN i_cursor%NOTFOUND;
PIPE ROW (table_name_type(v_a, v_b, v_c));
END LOOP;
CLOSE i_cursor;
EXCEPTION
WHEN NO_DATA_NEEDED THEN
CLOSE i_cursor;
WHEN OTHERS THEN
CLOSE i_cursor;
RAISE;
END;
/
Which then allows you to use the returned pipelined collection in an SQL statement and read one cursor into another cursor and apply filters to it:
CREATE PROCEDURE wrap_cursor_proc (
i_cursor IN SYS_REFCURSOR,
o_cursor OUT SYS_REFCURSOR
)
IS
BEGIN
OPEN o_cursor FOR
SELECT *
FROM TABLE(wrap_cursor_fn(i_cursor))
WHERE MOD(a, 3) = 0;
END;
/
Which you can then read:
DECLARE
v_cur1 SYS_REFCURSOR;
v_cur2 SYS_REFCURSOR;
v_a table_name.a%TYPE;
v_b table_name.b%TYPE;
v_c table_name.c%TYPE;
BEGIN
get_cursor(v_cur1);
wrap_cursor_proc(v_cur1, v_cur2);
LOOP
FETCH v_cur2 INTO v_a, v_b, v_c;
EXIT WHEN v_cur2%NOTFOUND;
DBMS_OUTPUT.PUT_LINE( v_a || ', ' || v_b || ', ' || v_c );
END LOOP;
CLOSE v_cur2;
END;
/
and outputs:
3, C, 03-JAN-70
6, F, 06-JAN-70
9, I, 09-JAN-70
fiddle
It is a lot of work to read a cursor within the database and get it back into a format that can be used in an SQL query so that you can wrap it in another cursor just to apply a filter. It would be much simpler to just duplicate the original procedure and add the necessary filter condition to it.

oracle stored procedure return resultset

Can I define the stored procedure without using the RefCursor ? (like "return refcursor")
I do not want to use OracleDbType.RefCursor because it is not sent as dbparameter in other databases.
Also DbParameter.DbType = OracleDbType.RefCursor; does not supported
I do not want to define "retval IN OUT SYS_REFCURSOR" in the code below. Is there another way?
CREATE OR REPLACE procedure SYSTEM.customer_select_row(
p_email IN CUSTOMER.Email%TYPE,
p_password IN CUSTOMER."Password"%TYPE,
retval IN OUT SYS_REFCURSOR
)
IS
BEGIN
OPEN retval FOR
SELECT CustomerId, FirstName, LastName FROM CUSTOMER
WHERE Email = p_email AND "Password" = p_password
END customer_select_row;
You could use a pipeline Function,
It is a function that works exacltly as a table
you can call it this way
SELECT *
FROM TABLE(TEST_PIPELINE.STOCKPIVOT(10));
the TEST_PIPELINE.STOCKPIVOT(10) is a function
you can build it this way:
create or replace PACKAGE TEST_PIPELINE AS
-- here you declare a type record
type t_record is record
(
field_1 VARCHAR2(100),
field_2 VARCHAR2(100));
-- declare a table type from your previously created type
TYPE t_collection IS TABLE OF t_record;
-- declare that the function will return the collection pipelined
FUNCTION StockPivot(P_LINES NUMBER) RETURN t_collection PIPELINED;
END;
/
create or replace PACKAGE BODY TEST_PIPELINE IS
FUNCTION StockPivot(P_LINES NUMBER) RETURN t_collection PIPELINED IS
-- declare here a type of the record
T_LINE T_RECORD;
BEGIN
-- here is a loop example for insert some lines on pipeline
FOR I IN 1..P_LINES LOOP
-- inser data on your line this way
T_LINE.field_1 := 'LINE - ' || I;
T_LINE.field_2 := 'LINE - ' || I;
-- then insert insert the line for result (this kind of functions should not have a return statement)
PIPE ROW (T_LINE );
END LOOP;
END;
END;

Can I write the stored procedure with table as output parameter as a single query in Oracle?

I have a C# method which takes a SQL string statement and saves the data into xml format.
public XmlDocument GetDBRequestXml(String sql)
{
}
I have a stored procedure with output parameter as table. Is there any way to pass this stored procedure as an executable single SQL statement in the above C# method? Can somebody please help me on this!!!
create or replace PACKAGE BODY EMPLOYEE_DETAILS AS
PROCEDURE GET_EMPLOYEES(
EMP_DEPT_ID EMPLOYEES.DEPARTMENT_ID%TYPE,
EMP_SALARY employees.salary%TYPE,
TBL_EMPLOYEES OUT TABLE_EMPLOYEES)
IS
LC_SELECT SYS_REFCURSOR;
LR_DETAILS DETAILS;
TBL_EMPLOYEE EMPLOYEE_DETAILS.TABLE_EMPLOYEES := EMPLOYEE_DETAILS.TABLE_EMPLOYEES();
BEGIN
OPEN LC_SELECT FOR
SELECT EMPLOYEE_ID, FIRST_NAME, LAST_NAME
FROM EMPLOYEES
WHERE DEPARTMENT_ID = EMP_DEPT_ID AND
EMPLOYEES.SALARY > EMP_SALARY;
LOOP
FETCH LC_SELECT INTO LR_DETAILS;
EXIT WHEN LC_SELECT%NOTFOUND;
IF LR_DETAILS.EMPLOYEE_ID > 114 THEN
TBL_EMPLOYEE.extend();
TBL_EMPLOYEE(TBL_EMPLOYEE.count()) := LR_DETAILS;
END IF;
END LOOP;
CLOSE LC_SELECT;
TBL_EMPLOYEES := TBL_EMPLOYEE;
END GET_EMPLOYEES;
END EMPLOYEE_DETAILS;
I had a good run at this today. I don't know if you still need it but this is good to understand. You can output this from stored proc:
CREATE OR REPLACE PACKAGE Eidmadm.TestPkg AS
TYPE stringTbl IS TABLE OF varchar2(250) INDEX BY BINARY_INTEGER;
PROCEDURE TestProc (p_strings out stringTbl );
END;
The other table, like below, didn't work
TYPE numTbl IS TABLE OF varchar2(100);
The c# code for this is:
OracleParameter p2 = new OracleParameter(":p_strings", OracleDbType.Varchar2, ParameterDirection.Output);
p2.CollectionType = OracleCollectionType.PLSQLAssociativeArray;
p2.Size = 100; // allocate enough extra space to retrieve expected result
// assign amount of space for each member of returning array
p2.ArrayBindSize = Enumerable.Repeat(250, 100).ToArray();
cmd.Parameters.Add(p2);
cmd.ExecuteNonQuery();
// And this is how you retrieve values
OracleString[] oraStrings = (OracleString[])p2.Value;
string[] myP2Values = new string[oraStrings.Length];
for (int i = 0; i < oraNumbers.Length; i++)
myP2Values[i] = oraStrings[i].Value;
**But most important is this: **
When you fill your pl/sql table, it needs to start from something larger than `0`, and preferably from `1`. Because and also - if you have index with skipped numbers, i.e. `2,4,6,8`, all those spaces will be part of returning `oracle array` and there will be `oracle null` in them. You would need to check for `null` in your loop
if !oraStrings[i].IsNull {....}
else {....}
Enjoy!

Pass a list of integers from C# into Oracle stored procedure

I have a oracle stored procedure which updates a table with the following statement.
update boxes
set location = 'some value'
where boxid = passed value
I have a page where the user selects 100+ boxes and updates them with a new location value. Currently, I have to call the stored procedure 100+ times to update each box(by passing a boxid each time).
I want to know how I can pass a list of boxids from C# into the stored procedure so that I have to call the stored procedure just one time.
I am hoping to use a where in(boxids) kind of where clause in the update statement.
Please let know how can I achieve this. Thanks in advance!
Oracle allows you to pass arrays of values as parameters. Borrowing from this SO question and this one you can define an INT_ARRAY type like this:
create or replace type CHAR_ARRAY as table of INTEGER;
Then define your stored procedure as:
CREATE OR REPLACE PROCEDURE product_search(
...
myIds IN CHAR_ARRAY,
...)
AS
SELECT ...
...
WHERE SomeIdField IN (Select column_value FROM TABLE(myIds))
...
You can then pass the list of values by setting the OracleParameter.CollectionType property like this:
OracleParameter param = new OracleParameter();
param.OracleDbType = OracleDbType.Int32;
param.CollectionType = OracleCollectionType.PLSQLAssociativeArray;
I'd create a new procedure, designed to handle a list of values. An efficient approach would be to load the multiple values into a global temp table, using a bulk insert, and then have the procedure update using a join to the GTT.
A notional example would look like this:
OracleTransaction trans = conn.BeginTransaction(IsolationLevel.RepeatableRead);
OracleCommand cmd = new OracleCommand(insertSql, conn, trans);
cmd.Parameters.Add(new OracleParameter("BOX_ID", OracleDbType.Number));
cmd.Parameters[0].Value = listOfBoxIds; // int[] listOfBoxIds;
cmd.ExecuteArray();
OracleCommand cmd2 = new OracleCommand(storedProc, conn, trans);
cmd2.CommandType = CommandType.StoredProcedure;
cmd2.ExecuteNonQuery();
trans.Commit();
Your PL/SQL block may look like this one:
CREATE OR REPLACE PACKAGE YOUR_PACKAGE AS
TYPE TArrayOfNumber IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
PROCEDURE Update_Boxes(boxes IN TArrayOfNumber );
END YOUR_PACKAGE;
/
CREATE OR REPLACE PACKAGE BODY YOUR_PACKAGE AS
PROCEDURE Update_Boxes(boxes IN TArrayOfNumber) is
BEGIN
FORALL i IN INDICES OF boxes
update boxes
set location = boxes(i)
where boxid = ...;
END Update_Boxes;
END YOUR_PACKAGE;
The C# code you get already in answer from Panagiotis Kanavos
I understand your concern - the round trips will be taxing.
Unfortunately I don't have anything to test, but you can try
Oracle bulk updates using ODP.NET
or
-- edit1: go with Panagiotis Kanavos's answer if your provider supports it, else check below --
-- edit12 as highlighted by Wernfried, long is deprecated. Another thing consider is max length varchar2: it doesn't scale on a very big set. Use the one below as the last resort. --
changing your stored procedure to accept string
implement string_2_list in asktom.oracle.com.
create or replace type myTableType as table of varchar2 (255);
create or replace function in_list( p_string in varchar2 ) return myTableType
as
l_string long default p_string || ',';
l_data myTableType := myTableType();
n number;
begin
loop
exit when l_string is null;
n := instr( l_string, ',' );
l_data.extend;
l_data(l_data.count) :=
ltrim( rtrim( substr( l_string, 1, n-1 ) ) );
l_string := substr( l_string, n+1 );
end loop;
return l_data;
end;
Above is early variant and splice to varchar2, but if you read more (including other threads) at that site
you'll find more advanced variants (optimized, better exception handling)

Oracle Parameters with IN statement?

Got a c#.net app which I need to modify. The query at the moment effectively does this:
select * from contract where contractnum = :ContractNum
(very simplified, just to show we're using an = and one parameter)
That parameter is read in from the Settings.Settings file on the C# app and has one string in it. I need to modify it to include multiple contracts, so I figure I can change the SQL to:
select * from contract where contractnum in (:ContractNum)
but that returns no results, no matter how I format the string in the parameter.
Is there a way I can get oracle to do an IN with a parameter?
You can use an Oracle collection of numbers as a parameter (bind variable) when you use ODP.NET as dataprovider. This works with Oracle server 9, 10 or 11 and ODP.net release >= 11.1.0.6.20 .
A similar solution is possible when you use Devart's .NET dataprovider for Oracle.
Let's select the contracts with contractnum's 3 and 4.
We have to use an Oracle type to transfer an array of contract numbers to our query.
MDSYS.SDO_ELEM_INFO_ARRAY is used because if we use this already predefined Oracle type we don't have to define our own Oracle type. You can fill MDSYS.SDO_ELEM_INFO_ARRAY with max 1048576 numbers.
using Oracle.DataAccess.Client;
using Oracle.DataAccess.Types;
[OracleCustomTypeMappingAttribute("MDSYS.SDO_ELEM_INFO_ARRAY")]
public class NumberArrayFactory : IOracleArrayTypeFactory
{
public Array CreateArray(int numElems)
{
return new Decimal[numElems];
}
public Array CreateStatusArray(int numElems)
{
return null;
}
}
private void Test()
{
OracleConnectionStringBuilder b = new OracleConnectionStringBuilder();
b.UserID = "sna";
b.Password = "sna";
b.DataSource = "ora11";
using (OracleConnection conn = new OracleConnection(b.ToString()))
{
conn.Open();
using (OracleCommand comm = conn.CreateCommand())
{
comm.CommandText =
#" select /*+ cardinality(tab 10) */ c.* " +
#" from contract c, table(:1) tab " +
#" where c.contractnum = tab.column_value";
OracleParameter p = new OracleParameter();
p.OracleDbType = OracleDbType.Array;
p.Direction = ParameterDirection.Input;
p.UdtTypeName = "MDSYS.SDO_ELEM_INFO_ARRAY";
//select contract 3 and 4
p.Value = new Decimal[] { 3, 4 };
comm.Parameters.Add(p);
int numContracts = 0;
using (OracleDataReader reader = comm.ExecuteReader())
{
while (reader.Read())
{
numContracts++;
}
}
conn.Close();
}
}
}
The index on contract.contractnum isn't used when one omits hint /*+ cardinality(tab 10) */. I assumed contractnum is the primary key so this column will be indexed.
See also here: http://forums.oracle.com/forums/thread.jspa?messageID=3869879#3869879
you could use a pipelined function to transform a string into a table which could be used with the IN operator. For example (tested with 10gR2):
SQL> select * from table(demo_pkg.string_to_tab('i,j,k'));
COLUMN_VALUE
-----------------
i
j
k
with the following package:
SQL> CREATE OR REPLACE PACKAGE demo_pkg IS
2 TYPE varchar_tab IS TABLE OF VARCHAR2(4000);
3 FUNCTION string_to_tab(p_string VARCHAR2,
4 p_delimiter VARCHAR2 DEFAULT ',')
5 RETURN varchar_tab PIPELINED;
6 END demo_pkg;
7 /
Package created
SQL> CREATE OR REPLACE PACKAGE BODY demo_pkg IS
2 FUNCTION string_to_tab(p_string VARCHAR2,
3 p_delimiter VARCHAR2 DEFAULT ',')
4 RETURN varchar_tab PIPELINED IS
5 l_string VARCHAR2(4000) := p_string;
6 l_first_delimiter NUMBER := instr(p_string, p_delimiter);
7 BEGIN
8 LOOP
9 IF nvl(l_first_delimiter,0) = 0 THEN
10 PIPE ROW(l_string);
11 RETURN;
12 END IF;
13 PIPE ROW(substr(l_string, 1, l_first_delimiter - 1));
14 l_string := substr(l_string, l_first_delimiter + 1);
15 l_first_delimiter := instr(l_string, p_delimiter);
16 END LOOP;
17 END;
18 END demo_pkg;
19 /
Package body created
Your query would look like this:
select *
from contract
where contractnum in (select column_value
from table(demo_pkg.string_to_tab(:ContractNum)))
Have yet to find a db that supports evaluating a single string variable containing commas to separate as the sole IN clause.
Your options are to substring the variable so the comma delimited variable contents are turned into rows, so you can then join onto this. Or to use dynamic SQL, which is a SQL statement constructed as a string in a sproc before the statement is executed.
I know this is an old question but it is one of several in which the selected answer did not solve my problem and I don't want to start yet another thread on this topic so I'll just put down what I found in my travels in the hope that it might help someone.
I don't work with Oracle much but, like in SQL Server, it seems that to pass a table-valued parameter you need to have a corresponding UDT (user defined table) to which you have EXECUTE permissions (I could be wrong). This means that other answers suggesting the use of a built-in SYS UDT come with some freight and I couldn't figure out whether it really is possible to pass a table to something that is not a PL/SQL stored procedure in the current version of ODP.net.
Second, the string-parse solution is a kludge for all the obvious reasons (can't cache the execution plan or whatever Oracle calls it, doesn't scale well, etc).
So I spent rather a lot of time trying do the IN-clause using a table-valued parameter on a datamart to which I have only READ permission before I was hit by a blinding flash of the obvious (At an ASP.net forum no less). Turns out Oracle supports Xml queries 'natively' so instead of passing an array of values you can pass an xml list (if that is all you need). Again, I may be wrong, but it gets handled as a legitimate bind parameter and this is an example of how simple it is to use (vb.net, ADO.net, ODP.net using NuGet package):
Dim xe As New XElement("l", New XElement("i", "ITEM-A"), New XElement("i", "ITEM-B"))
Using conn As New OracleConnection(myConnectionString)
conn.Open()
Using cmd As OracleCommand = conn.CreateCommand()
cmd.CommandType = CommandType.Text
Dim query As String
query = " SELECT s.FOO, q.BAR " & vbCrLf
query &= " FROM TABLE1 s LEFT OUTER JOIN " & vbCrLf
query &= " TABLE2 q ON q.ID = s.ID " & vbCrLf
query &= " WHERE (COALESCE(q.ID, 'NULL') NOT LIKE '%OPTIONAL%') AND "
query &= " (s.ID IN ("
query &= " SELECT stid "
query &= " FROM XMLTable('/l/i' PASSING XMLTYPE(:stid) COLUMNS stid VARCHAR(32) PATH '.')"
query &= " )"
query &= " )"
cmd.CommandText = query
Dim parameter As OracleParameter = cmd.Parameters.Add("stid", OracleDbType.NVarchar2, 4000)
parameter.Value = xe.ToString
Using r As OracleDataReader = cmd.ExecuteReader
While r.Read()
//Do something
End While
End Using
End Using
conn.Close()
This is more of an observation than a carefully researched solution so please comment if there is anything inappropriate about doing it this way.
There is apparently a 4000 character limit using this method (2000 if NVARCHAR) so I had to watch my paging. The informative error message you get if you go over is
ORA-01460: unimplemented or unreasonable conversion requested
For using parameter with IN statement you can use this construction:
select * from contract where contractnum
in (select column_value from table (:ContractNum))
where ContractNum is the custom array type.
Maybe someone is still looking for an answer, here's an example with rexexp.
https://blogs.oracle.com/aramamoo/passing-comma-separated-string-as-bind-variable-for-vo-querys-in-operator-v2
In this case, each emp no is coma separated
WHERE Emp.ENAME in
(select regexp_substr(:Bind_Ename_Comma_Sep_List,'[^,]+', 1, level)
from dual
connect by
regexp_substr(:Bind_Ename_Comma_Sep_List, '[^,]+', 1, level)
is not null)
Another way is to use the INSTR function: For example if the comma delimited data is in :xyz then you can determine if a value in a named item fldOne is in that list as follows:
INSTR(',' || :xyz || ',', ',' || fldOne ||',') > 0
will return true if the value fldOne references is in the list and false otherwise.
Of course, if you want to match against an explicit string, then you can replace fldOne with 'value'.
BTW this will also work if you created a comma separated variable using ListAgg or any other mechanism.
If the comma separated list was named MyList then just replace :xyz above with MyList.

Categories