What are the best workarounds for using a SQL IN clause with instances of java.sql.PreparedStatement, which is not supported for multiple values due to SQL injection attack security issues: One ? placeholder represents one value, rather than a list of values.
Consider the following SQL statement:
SELECT my_column FROM my_table where search_column IN (?)
Using preparedStatement.setString( 1, ''A', 'B', 'C'' ); is essentially a non-working attempt at a workaround of the reasons for using ? in the first place.
What workarounds are available?
An analysis of the various options available, and the pros and cons of each is available in Jeanne Boyarsky’s Batching Select Statements in JDBC entry on JavaRanch Journal.
The suggested options are:
SELECT my_column FROM my_table WHERE search_column = ?, execute it for each value and UNION the results client-side. Requires only one prepared statement. Slow and painful.SELECT my_column FROM my_table WHERE search_column IN (?,?,?)and execute it. Requires one prepared statement per size-of-IN-list. Fast and obvious.SELECT my_column FROM my_table WHERE search_column = ? ; SELECT my_column FROM my_table WHERE search_column = ? ; ...and execute it. [Or useUNION ALLin place of those semicolons. –ed] Requires one prepared statement per size-of-IN-list. Stupidly slow, strictly worse thanWHERE search_column IN (?,?,?), so I don’t know why the blogger even suggested it.SELECT my_column FROM my_table WHERE search_column IN (1,2,3,4,5,6,6,6,6,6). Any decent server will optimize out the duplicate values before running the query.None of these options are ideal.
The best option if you are using JDBC4 and a server that supports
x = ANY(y), is to usePreparedStatement.setArrayas described in Boris’s anwser.There doesn’t seem to be any way to make
setArraywork with IN-lists, though.Sometimes SQL statements are loaded at runtime (e.g., from a properties file) but require a variable number of parameters. In such cases, first define the query:
Next, load the query. Then determine the number of parameters prior to running it. Once the parameter count is known, run:
For example:
For certain databases where passing an array via the JDBC 4 specification is unsupported, this method can facilitate transforming the slow
= ?into the fasterIN (?)clause condition, which can then be expanded by calling theanymethod.