35

i have a list of names e.g.:

List<String> names = ...
names.add('charles');
...

and a statement:

PreparedStatement stmt = 
  conn.prepareStatement('select * from person where name in ( ? )');

how to do the following:

stmt.setParameterList(1,names);

Is there a workaround? can someone explain why this method is missing?

using: java, postgresql, jdbc3

Chris
  • 15,429
  • 19
  • 72
  • 74

8 Answers8

23

This question is very old, but nobody has suggested using setArray

This answer might help https://stackoverflow.com/a/10240302/573057

Leif Jones
  • 320
  • 6
  • 21
earcam
  • 6,662
  • 4
  • 37
  • 57
  • 6
    setArray won't work with MySQL or JavaDB as they don't support the ARRAY data type in SQL. See the note at the top of: https://docs.oracle.com/javase/tutorial/jdbc/basics/array.html – TigerC10 Aug 09 '17 at 17:47
  • @TigerC10 good point ... curiosity piqued re: Java in-memory dB - Derby (JavaDB) doesn't support but both [h2](http://www.h2database.com/html/datatypes.html#array_type) and [hsqldb](http://hsqldb.org/doc/guide/sqlgeneral-chapt.html#sgc_array) do. – earcam Aug 14 '17 at 00:00
21

There's no clean way to do this simply by setting a list on the PreparedStatement that I know of.

Write code that constructs the SQL statement (or better replaces a single ? or similar token) with the appropriate number of questions marks (the same number as in your list) and then iterate over your list setting the parameter for each.

Nick Holt
  • 33,455
  • 4
  • 52
  • 58
2

this method is missing due to type erasure the parameter type of the List is lost at runtime. Therefore the need to add several methods arires: setIntParameters, setLongParameters, setObjectParameters, etc

dfa
  • 114,442
  • 31
  • 189
  • 228
  • if there is a add method for every data type, why isn't there a 'addList' method for every datatype too? (e.g. addStringList(...)) – Chris Aug 22 '09 at 11:44
  • this is the point, the Statement interface is already bloated even without counting list variants – dfa Aug 22 '09 at 14:11
  • 3
    Type erasure is not a good reason, there could be setArrayParameter(int pos, Object[] params) – jnr Nov 30 '10 at 13:17
1

For postgres 9 I have used this approach:

 jdbcTemplate.query(getEmployeeReport(), new PreparedStatementSetter() {
        @Override
        public void setValues(PreparedStatement ps) throws SQLException {
            ps.setTimestamp(1, new java.sql.Timestamp(from.getTime()));
            ps.setTimestamp(2, new java.sql.Timestamp(to.getTime()));
            StringBuilder ids = new StringBuilder();
            for (int i = 0; i < branchIds.length; i++) {
                ids.append(branchIds[i]);
                if (i < branchIds.length - 1) {
                    ids.append(",");
                }
            }
            // third param is inside IN clause
            // Use Types.OTHER avoid type check while executing query  
            ps.setObject(3, ids.toString(), **Types.OTHER**);
        }
    }, new PersonalReportMapper());
junior
  • 27
  • 1
  • Does this really work for `in (?)`? What does the actual statement look like once it's issued to the server? – rbellamy Feb 07 '16 at 08:14
  • 1
    You want to avoid concatenation of string values in your JDBC code, as that might easily lead to SQL injection bugs. -1 – Bastian Voigt Nov 29 '17 at 10:23
0

In case the questions' meaning is to set several params in a single call...

Because the type validation is already defined in a higher level, I think the only need is for setObject(...).

Thus, a utility method can be used:

public static void addParams(PreparedStatement preparedStatement, Object... params) throws SQLException {
    for (int i = 0; i < params.length; i++) {
        Object param = params[i];
        preparedStatement.setObject(i+1, param);
    }
}

Usage:

SqlUtils.addParams(preparedStatement, 1, '2', 3d);

Feel free converting this to a Java 8 lambda :)

AlikElzin-kilaka
  • 34,335
  • 35
  • 194
  • 277
-1

I was reviewing code this morning and one of my colleagues had a different approach, just pass the parameter using setString("name1','name2','name3").

Note: I skipped the single quote at the beginning and end because these are going to be added by the setString.

Littm
  • 4,923
  • 4
  • 30
  • 38
  • 1
    For constant strings, it might be acceptable. For user input, it is a nice example of code vulnerable to SQL injection. – Ondřej Bouda Feb 13 '13 at 05:00
  • This absolutely should not work. If it does, there's a bug in your JDBC driver. `setString` deals with the apostrophes, so that you actually get the `String` that you passed. Had your colleague tested their code? – Dawood ibn Kareem Aug 28 '14 at 00:33
-1

After examining various solutions in different forums and not finding a good solution, I feel the below hack I came up with, is the easiest to follow and code. Note however that this doesn't use prepared query but gets the work done anyway:

Example: Suppose you have a list of parameters to pass in the 'IN' clause. Just put a dummy String inside the 'IN' clause, say, "PARAM" do denote the list of parameters that will be coming in the place of this dummy String.

    select * from TABLE_A where ATTR IN (PARAM);

You can collect all the parameters into a single String variable in your Java code. This can be done as follows:

    String param1 = "X";
    String param2 = "Y";
    String param1 = param1.append(",").append(param2);

You can append all your parameters separated by commas into a single String variable, 'param1', in our case.

After collecting all the parameters into a single String you can just replace the dummy text in your query, i.e., "PARAM" in this case, with the parameter String, i.e., param1. Here is what you need to do:

    String query = query.replaceFirst("PARAM",param1); where we have the value of query as 

    query = "select * from TABLE_A where ATTR IN (PARAM)";

You can now execute your query using the executeQuery() method. Just make sure that you don't have the word "PARAM" in your query anywhere. You can use a combination of special characters and alphabets instead of the word "PARAM" in order to make sure that there is no possibility of such a word coming in the query. Hope you got the solution.

bnsk
  • 131
  • 9
-3

Other method :

public void setValues(PreparedStatement ps) throws SQLException {
    // first param inside IN clause with myList values
    ps.setObject(1 , myList.toArray(), 2003); // 2003=array in java.sql.Types
}