I've been searching for a while now for a way to execute a select statement on an oracle database which contains an arbitray number of elements in the where clause.
In principle what I want to do is something like this:

select * from my_table
where my_col in (:inputListHere)

Looking around I found the following solutions, none of which seem to properly work:

Using dynamic sql and just insert the list as a string of comma seperated elements.
Works only for short lists. Long lists break the 4000 char limit for command string literals. (Btw.: I don't need to worry about sql injection attacks, so in principle dynamic sql would be an option.)

Using associative arrays in a stored proc. From what I could find the only way to use associative arrays in a stored proc is to iterate over them but that would give terrible performance when I want to get all the differenct occurence of elements in a list in a table.

Using bind arrays with a stored proc. Same issue here: Since the stored proc is called once for every element in the bind array the performance is terrible.

Inserting the list that I want to use in the where clause into the db beforehand and then executing a query which has something like select list_items from tmp_list_store in place of :inputListHere. The performance here turned out to be better than for option 2. and 3. but worse than for option 1 and an additional disadvantage is that the user that executes the query needs to have write access to this one table on the database even though he just wants to read from the db.

If you have any better options or ideas how to improve upon one of these options it would be much appreciated.

2 Answers
2

After gaining a bit more Database knowledge in the past half year I have come to the following conclusion:
As far as a solution to the problem I proposed goes the answer that HABJAN gave in addition to the options I proposed are probably the most reasonable solutions.
The reason why none of those solutions are quite working out is because the correct answer, I think, is that if you have a couple of thousand items to transfer you shouldn't have them as parameters but as values in a separate table in the database. Otherwise the design should probably be rethought.
In that sense option 4 is probably closest to the correct answer but not having the problem at all because you improve your design is probably the best answer.

You can use a predefined type and skip steps 1 and 2. select * from my_table where my_col in (select * from table(sys.odcivarchar2list('value1', 'value1', 'value2', 'value4', 'value5')));
–
Jon HellerApr 1 '11 at 17:52

@jonearles: the problem is that his procedure gets: "'value1', 'value1', 'value2', 'value4', 'value5'" as one value/varchar.
–
HABJANApr 1 '11 at 18:01

You're right. You'd have to use dynamic sql (with concatenation, not a bind) to get it to work, and each individual input value would have be surrounded by single quotes.
–
Jon HellerApr 1 '11 at 19:21

Which would basically mean that I have to take a list and convert it to a concatenated string program side to then again split it into separate items on the db side. Probably as far away from type safety as possible. I was hoping there would be a cleaner solution which I just haven't found yet.
–
CorneliusApr 1 '11 at 21:31

@Cornelius Mund: i totally forgot about one more way how to accomplish what you need. I changed my answer. Take a look.
–
HABJANApr 1 '11 at 22:16