PreparedStatement со списком параметров в предложении IN

Как установить значение для предложения in в подготовленном состоянии в JDBC во время выполнения запроса.

Пример:

connection.prepareStatement("Select * from test where field in (?)"); 

Если это предложение внутри может содержать несколько значений, как я могу это сделать. Иногда я заранее знаю список параметров или иногда не знаю заранее. Как справиться с этим делом?

Что я делаю, это добавить «?» для каждого возможного значения.

Для instace:

 List possibleValues = ... StringBuilder builder = new StringBuilder(); for( int i = 0 ; i < possibleValue.size(); i++ ) { builder.append("?,"); } String stmt = "select * from test where field in " + builder.deleteCharAt( builder.length() -1 ).toString(); PreparedStatement pstmt = ... 

И затем счастливо установите параметры

 int index = 1; for( Object o : possibleValue ) { pstmt.setObject( index++, o ); // or whatever it applies } 

Вы можете использовать метод setArray как указано в javadoc ниже:

http://docs.oracle.com/javase/6/docs/api/java/sql/PreparedStatement.html#setArray (int, java.sql.Array)

Код:

 PreparedStatement statement = connection.prepareStatement("Select * from test where field in (?)"); Array array = statement.getConnection().createArrayOf("VARCHAR", new Object[]{"A1", "B2","C3"}); statement.setArray(1, array); ResultSet rs = statement.executeQuery(); 

Вы можете проверить эту ссылку:

http://www.javaranch.com/journal/200510/Journal200510.jsp#a2

В нем объясняются плюсы и минусы различных методов создания PreparedStatement in разделе.

РЕДАКТИРОВАТЬ:

Очевидным подходом является динамическое генерирование ‘?’ во время выполнения, но я не хочу просто предлагать именно этот подход, потому что в зависимости от того, как вы его используете, он может быть неэффективным (поскольку PreparedStatement нужно будет «скомпилировать» каждый раз, когда он будет использоваться)

Вы не можете заменить ? в вашем запросе с произвольным количеством значений. Каждый ? является заполнителем только для одного значения. Чтобы поддерживать произвольное количество значений, вам придется динамически строить строку, содержащую ?, ?, ?, ... , ? при этом количество вопросительных знаков будет таким же, как количество значений, которое вы хотите в своем разделе.

Вам нужен jdbc4, тогда вы можете использовать setArray!

В моем случае это не сработало, поскольку у UDID Datatype в postgres, похоже, все еще есть свои слабые места, но для обычных типов он работает.

 ps.setArray(1, connection.createArrayOf("$VALUETYPE",myValuesAsArray)); 

Конечно, замените $ VALUETYPE и myValuesAsArray с правильными значениями.

Замечание следующего комментария Marks:

Ваша firebase database и драйвер должны поддерживать это! Я пробовал Postgres 9.4, но я думаю, что это было введено ранее. Вам нужен драйвер jdbc 4, иначе setArray не будет доступен. Я использовал драйвер postgresql 9.4-1201-jdbc41, который поставляется с весенним ботинком

То, что вы можете сделать, – это динамически построить строку выбора (часть «IN (?)» Простым циклом цикла, как только вы знаете, сколько значений нужно разместить внутри предложения IN. Затем вы можете создать экземпляр PreparedStatement.

Вы не хотите использовать PreparedStatment с динамическими запросами, используя предложение IN, по крайней мере, вы уверены, что всегда находитесь под 5 переменными или небольшим значением, но даже, как мне кажется, это плохая идея (не ужасная, но плохая). Поскольку количество элементов велико, это будет хуже (и ужасно).

Представьте себе сто или тысячи возможностей в вашем разделе IN:

  1. Это контрпродуктивно, вы потеряли производительность и память, потому что кешируете каждый раз новый запрос, а PreparedStatement – не только для SQL-инъекций, но и производительности. В этом случае утверждение лучше.

  2. У вашего пула есть предел PreparedStatment (-1 defaut, но вы должны его ограничить), и вы достигнете этого предела! и если у вас нет предела или очень большого предела, у вас есть некоторый риск утечки памяти и в крайнем случае ошибки OutofMemory. Так что если это для вашего небольшого индивидуального проекта, используемого тремя пользователями, это не драматично, но вы не хотите, чтобы, если вы в большой компании и что вы используете приложение, используется тысячами людей и миллионным запросом.

Некоторые чтения. IBM: соображения использования памяти при использовании готового кэширования инструкций

 public static ResultSet getResult(Connection connection, List values) { try { String queryString = "Select * from table_name where column_name in"; StringBuilder parameterBuilder = new StringBuilder(); parameterBuilder.append(" ("); for (int i = 0; i < values.size(); i++) { parameterBuilder.append("?"); if (values.size() > i + 1) { parameterBuilder.append(","); } } parameterBuilder.append(")"); PreparedStatement statement = connection.prepareStatement(queryString + parameterBuilder); for (int i = 1; i < values.size() + 1; i++) { statement.setInt(i, (int) values.get(i - 1)); } return statement.executeQuery(); } catch (Exception d) { return null; } } 

В настоящее время MySQL не позволяет устанавливать несколько значений в одном вызове метода. Поэтому вы должны иметь это под своим контролем. Обычно я создаю один подготовленный оператор для предопределенного количества параметров, затем добавляю столько партий, сколько мне нужно.

  int paramSizeInClause = 10; // required to be greater than 0! String color = "FF0000"; // red String name = "Nathan"; Date now = new Date(); String[] ids = "15,21,45,48,77,145,158,321,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,358,1284,1587".split(","); // Build sql query StringBuilder sql = new StringBuilder(); sql.append("UPDATE book SET color=? update_by=?, update_date=? WHERE book_id in ("); // number of max params in IN clause can be modified // to get most efficient combination of number of batches // and number of parameters in each batch for (int n = 0; n < paramSizeInClause; n++) { sql.append("?,"); } if (sql.length() > 0) { sql.deleteCharAt(sql.lastIndexOf(",")); } sql.append(")"); PreparedStatement pstm = null; try { pstm = connection.prepareStatement(sql.toString()); int totalIdsToProcess = ids.length; int batchLoops = totalIdsToProcess / paramSizeInClause + (totalIdsToProcess % paramSizeInClause > 0 ? 1 : 0); for (int l = 0; l < batchLoops; l++) { int i = 1; pstm.setString(i++, color); pstm.setString(i++, name); pstm.setTimestamp(i++, new Timestamp(now.getTime())); for (int count = 0; count < paramSizeInClause; count++) { int param = (l * paramSizeInClause + count); if (param < totalIdsToProcess) { pstm.setString(i++, ids[param]); } else { pstm.setNull(i++, Types.VARCHAR); } } pstm.addBatch(); } } catch (SQLException e) { } finally { //close statement(s) } 

Если вам не нравится устанавливать NULL, когда больше не осталось параметров, вы можете изменить код для создания двух запросов и двух подготовленных операторов. Первый из них один и тот же, но второй оператор для остатка (модуль). В этом конкретном примере это будет один запрос для 10 параметров и один для 8 параметров. Вам нужно будет добавить 3 пакета для первого запроса (первые 30 параметров), затем одну партию для второго запроса (8 параметров).

 public class Test1 { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub System.out.println("helow"); String where="where task in "; where+="("; // where+="'task1'"; int num[]={1,2,3,4}; for (int i=0;i1 && i 

Вы можете использовать :

 for( int i = 0 ; i < listField.size(); i++ ) { i < listField.size() - 1 ? request.append("?,") : request.append("?"); } 

Затем :

 int i = 1; for (String field : listField) { statement.setString(i++, field); } 

Пример:

 List listField = new ArrayList(); listField.add("test1"); listField.add("test2"); listField.add("test3"); StringBuilder request = new StringBuilder("SELECT * FROM TABLE WHERE FIELD IN ("); for( int i = 0 ; i < listField.size(); i++ ) { request = i < (listField.size() - 1) ? request.append("?,") : request.append("?"); } DNAPreparedStatement statement = DNAPreparedStatement.newInstance(connection, request.toString); int i = 1; for (String field : listField) { statement.setString(i++, field); } ResultSet rs = statement.executeQuery(); 

public static void main (String arg []) {

  Connection connection = ConnectionManager.getConnection(); PreparedStatement pstmt = null; //if the field values are in ArrayList List fieldList = new ArrayList(); try { StringBuffer sb = new StringBuffer(); sb.append(" SELECT * \n"); sb.append(" FROM TEST \n"); sb.append(" WHERE FIELD IN ( \n"); for(int i = 0; i < fieldList.size(); i++) { if(i == 0) { sb.append(" '"+fieldList.get(i)+"' \n"); } else { sb.append(" ,'"+fieldList.get(i)+"' \n"); } } sb.append(" ) \n"); pstmt = connection.prepareStatement(sb.toString()); pstmt.executeQuery(); } catch (SQLException se) { se.printStackTrace(); } } 

попробуйте с этим кодом

  String ids[] = {"182","160","183"}; StringBuilder builder = new StringBuilder(); for( int i = 0 ; i < ids.length; i++ ) { builder.append("?,"); } String sql = "delete from emp where id in ("+builder.deleteCharAt( builder.length() -1 ).toString()+")"; PreparedStatement pstmt = connection.prepareStatement(sql); for (int i = 1; i <= ids.length; i++) { pstmt.setInt(i, Integer.parseInt(ids[i-1])); } int count = pstmt.executeUpdate(); 

У многих БД есть концепция временной таблицы, даже если у вас нет временной таблицы, вы всегда можете создать ее с уникальным именем и отбросить ее, когда закончите. Хотя накладные расходы на создание и удаление таблицы велики, это может быть разумно для очень больших операций или в тех случаях, когда вы используете базу данных как локальный файл или в памяти (SQLite).

Пример из того, что я нахожусь в середине (используя Java / SqlLite):

 String tmptable = "tmp" + UUID.randomUUID(); sql = "create table " + tmptable + "(pagelist text not null)"; cnn.createStatement().execute(sql); cnn.setAutoCommit(false); stmt = cnn.prepareStatement("insert into "+tmptable+" values(?);"); for(Object o : rmList){ Path path = (Path)o; stmt.setString(1, path.toString()); stmt.execute(); } cnn.commit(); cnn.setAutoCommit(true); stmt = cnn.prepareStatement(sql); stmt.execute("delete from filelist where path + page in (select * from "+tmptable+");"); stmt.execute("drop table "+tmptable+");"); 

Обратите внимание, что поля, используемые моей таблицей, создаются динамически.

Это будет еще более эффективным, если вы сможете повторно использовать таблицу.

 Using Java 8 APIs, List empNoList = Arrays.asList(1234, 7678, 2432, 9756556, 3354646); List parameters = new ArrayList<>(); empNoList.forEach(empNo -> parameters.add("?")); //Use forEach to add required no. of '?' String commaSepParameters = String.join(",", parameters); //Use String to join '?' with ',' StringBuilder selectQuery = new StringBuilder().append("SELECT COUNT(EMP_ID) FROM EMPLOYEE WHERE EMP_ID IN (").append(commaSepParameters).append(")"); 
Interesting Posts

Пользовательские страницы ошибок на asp.net MVC3

Ошибка: Ошибка выполнения для задачи «: app: dexDebug» в моем проекте, в то время как я добавил новую зависимость

Вызывается SSL-вызов Invoke-WebRequest?

Использование нескольких версий одной и той же библиотеки DLL

Часы Windows, показывающие как UTC, так и местное время?

Разница между объявлением переменных до или в цикле?

Пакеты NuGet отсутствуют

Как вы создаете запрос LINQ to Entities для непосредственного загрузки дочерних объектов, вместо вызова свойства Reference или Load ()

Двойные мониторы в Windows – Как установить другой размер DPI или текста на каждом мониторе?

Файл Java Jar: используйте ошибки ресурса: URI не является иерархическим

Предложение «ИЛИ» в папках поиска Outlook 2007 – состав папок

Приложение Excel VBA автоматически останавливается с сообщением «Выполнение кода приостановлено»

Как отобразить количество файлов в папке в проводнике Windows?

База данных Android SQLite: медленная вставка

Сброс пароля Windows 10 после обновления

Давайте будем гением компьютера.