Alternatives à la clause PreparedStatement IN?

Quelles sont les solutions les plus appropriées pour utiliser une clause SQL IN avec des instances de java.sql.PreparedStatement , qui n’est pas prise en charge pour plusieurs valeurs en raison de problèmes de sécurité liés à une attaque par injection SQL: Un ? placeholder représente une valeur plutôt qu’une liste de valeurs.

Considérez l’instruction SQL suivante:

 SELECT my_column FROM my_table where search_column IN (?) 

Utiliser preparedStatement.setSsortingng( 1, "'A', 'B', 'C'" ); est essentiellement une tentative non fonctionnelle de contourner les raisons de l’utilisation ? en premier lieu

Quelles solutions de contournement sont disponibles?

Une parsing des différentes options disponibles et des avantages et inconvénients de chacune est disponible ici .

Les options suggérées sont les suivantes:

  • Préparez SELECT my_column FROM my_table WHERE search_column = ? , l’exécuter pour chaque valeur et UNION les résultats côté client. Nécessite une seule déclaration préparée. Lente et douloureuse.
  • Préparez SELECT my_column FROM my_table WHERE search_column IN (?,?,?) Et exécutez-le. Nécessite une instruction préparée par taille de la liste IN. Rapide et évident.
  • Préparez SELECT my_column FROM my_table WHERE search_column = ? ; SELECT my_column FROM my_table WHERE search_column = ? ; ... SELECT my_column FROM my_table WHERE search_column = ? ; SELECT my_column FROM my_table WHERE search_column = ? ; ... SELECT my_column FROM my_table WHERE search_column = ? ; SELECT my_column FROM my_table WHERE search_column = ? ; ... et l’exécuter. [Ou utilisez UNION ALL à la place de ces points-virgules. –ed] Requiert une instruction préparée par taille de la liste IN. Stupidement lent, ssortingctement pire que WHERE search_column IN (?,?,?) , Donc je ne sais pas pourquoi le blogueur l’a même suggéré.
  • Utilisez une procédure stockée pour créer le jeu de résultats.
  • Préparer N différentes requêtes de taille d’IN-list; Par exemple, avec 2, 10 et 50 valeurs. Pour rechercher une liste avec 6 valeurs différentes, renseignez la taille-10 afin qu’elle ressemble à SELECT my_column FROM my_table WHERE search_column IN (1,2,3,4,5,6,6,6,6,6) . Tout serveur décent optimisera les valeurs en double avant d’exécuter la requête.

Aucune de ces options n’est super géniale, cependant.

Des questions en double ont été répondues dans ces endroits avec des alternatives tout aussi saines, mais aucune n’est encore géniale:

  • PreparedStatement avec liste de parameters dans une clause IN
  • Comment définir une liste de parameters sur une déclaration préparée?

La bonne réponse, si vous utilisez JDBC4 et un serveur prenant en charge x = ANY(y) , consiste à utiliser PreparedStatement.setArray comme décrit ici:

  • Alternatives à la clause PreparedStatement IN?

Cependant, il ne semble pas y avoir de moyen de faire en setArray que setArray fonctionne avec les listes IN.

Solution pour PostgreSQL:

 final PreparedStatement statement = connection.prepareStatement( "SELECT my_column FROM my_table where search_column = ANY (?)" ); final Ssortingng[] values = getValues(); statement.setArray(1, connection.createArrayOf("text", values)); final ResultSet rs = statement.executeQuery(); try { while(rs.next()) { // do some... } } finally { rs.close(); } 

ou

 final PreparedStatement statement = connection.prepareStatement( "SELECT my_column FROM my_table " + "where search_column IN (SELECT * FROM unnest(?))" ); final Ssortingng[] values = getValues(); statement.setArray(1, connection.createArrayOf("text", values)); final ResultSet rs = statement.executeQuery(); try { while(rs.next()) { // do some... } } finally { rs.close(); } 

Pas simple façon AFAIK. Si la cible est de conserver un ratio de cache d’instruction élevé (c’est-à-dire de ne pas créer une déclaration pour chaque nombre de parameters), vous pouvez procéder comme suit:

  1. créer une déclaration avec quelques parameters (par exemple 10):

    … O A UN IN (?,?,?,?,?,?,?,?,?,?) …

  2. Lier tous les parameters actuall

    setSsortingng (1, “foo”); setSsortingng (2, “bar”);

  3. Lier le rest comme NULL

    setNull (3, Types.VARCHAR) … setNull (10, Types.VARCHAR)

NULL ne correspond à rien, il est donc optimisé par le générateur de plan SQL.

La logique est facile à automatiser lorsque vous transmettez une liste à une fonction DAO:

 while( i < param.size() ) { ps.setString(i+1,param.get(i)); i++; } while( i < MAX_PARAMS ) { ps.setNull(i+1,Types.VARCHAR); i++; } 

Un travail désagréable, mais certainement réalisable, consiste à utiliser une requête nestede. Créez une table temporaire MYVALUES avec une colonne. Insérez votre liste de valeurs dans la table MYVALUES. Ensuite, exécutez

 select my_column from my_table where search_column in ( SELECT value FROM MYVALUES ) 

Moche, mais une alternative viable si votre liste de valeurs est très grande.

Cette technique présente l’avantage supplémentaire d’avoir de meilleurs plans de requêtes de l’optimiseur (vérifiez une page pour plusieurs valeurs, une seule fois par table, etc.) peut économiser sur les coûts si votre firebase database ne cache pas les instructions préparées. Votre “INSERTS” devra être fait en batch et la table MYVALUES devra peut-être être ajustée pour avoir un locking minimal ou d’autres protections à haut risque.

Les limitations de l’opérateur in () sont la racine de tout mal.

Cela fonctionne pour les cas sortingviaux, et vous pouvez l’étendre avec “génération automatique de l’instruction préparée”, mais elle a toujours ses limites.

  • si vous créez une instruction avec un nombre variable de parameters, cela provoquera une parsing SQL à chaque appel
  • sur de nombreuses plateformes, le nombre de parameters de l’opérateur in () est limité
  • sur toutes les plates-formes, la taille totale du texte SQL est limitée, rendant impossible l’envoi de 2 000 espaces réservés pour les parameters in
  • l’envoi de variables de liaison de 1000-10k n’est pas possible, car le pilote JDBC a ses limites

L’approche in () peut être suffisante dans certains cas, mais pas à l’épreuve des fusées 🙂

La solution anti-roquettes consiste à passer le nombre arbitraire de parameters dans un appel séparé (en passant un clob de parameters, par exemple), puis à afficher (ou toute autre manière) les représenter dans SQL et à les utiliser dans votre emplacement. Critères.

Une variante de force brute est ici http://tkyte.blogspot.hu/2006/06/varying-in-lists.html

Cependant, si vous pouvez utiliser PL / SQL, ce désordre peut devenir très intéressant.

 function getCustomers(in_customerIdList clob) return sys_refcursor is begin aux_in_list.parse(in_customerIdList); open res for select * from customer c, in_list v where c.customer_id=v.token; return res; end; 

Ensuite, vous pouvez transmettre un nombre arbitraire d’ID de client séparés par des virgules dans le paramètre et:

  • n’obtiendra aucun délai d’parsing, car le SQL pour select est stable
  • pas de complexité des fonctions en pipeline – ce n’est qu’une requête
  • le SQL utilise une simple jointure, au lieu d’un opérateur IN, ce qui est assez rapide
  • après tout, il est préférable de ne pas utiliser la firebase database avec un simple choix ou DML, car il s’agit d’Oracle, qui offre plus que MySQL ou des moteurs de firebase database simples similaires. PL / SQL vous permet de masquer le modèle de stockage de votre modèle de domaine d’application de manière efficace.

L’astuce ici est:

  • nous avons besoin d’un appel qui accepte la chaîne longue et stocke quelque part où la session de firebase database peut y accéder (par exemple, variable de package simple ou dbms_session.set_context)
  • alors nous avons besoin d’une vue qui peut parsingr ceci en lignes
  • et puis vous avez une vue qui contient les identifiants que vous interrogez, donc tout ce dont vous avez besoin est une simple jointure à la table interrogée.

La vue ressemble à:

 create or replace view in_list as select sortingm( substr (txt, instr (txt, ',', 1, level ) + 1, instr (txt, ',', 1, level+1) - instr (txt, ',', 1, level) -1 ) ) as token from (select ','||aux_in_list.getpayload||',' txt from dual) connect by level <= length(aux_in_list.getpayload)-length(replace(aux_in_list.getpayload,',',''))+1 

où aux_in_list.getpayload fait référence à la chaîne d'entrée d'origine.


Une approche possible serait de passer des tableaux pl / sql (pris en charge par Oracle uniquement), mais vous ne pouvez pas les utiliser en SQL pur. Par conséquent, une étape de conversion est toujours nécessaire. La conversion ne peut pas se faire en SQL, donc après tout, passer un clob avec tous les parameters dans ssortingng et le convertir en vue est la solution la plus efficace.

Je ne l’ai jamais essayé, mais est-ce que .setArray () ferait ce que vous cherchez?

Mise à jour : évidemment pas. setArray ne semble fonctionner qu’avec un java.sql.Array provenant d’une colonne ARRAY extraite d’une requête précédente ou une sous-requête avec une colonne ARRAY.

Ma solution de contournement est la suivante:

 create or replace type split_tbl as table of varchar(32767); / create or replace function split ( p_list varchar2, p_del varchar2 := ',' ) return split_tbl pipelined is l_idx pls_integer; l_list varchar2(32767) := p_list; l_value varchar2(32767); begin loop l_idx := instr(l_list,p_del); if l_idx > 0 then pipe row(substr(l_list,1,l_idx-1)); l_list := substr(l_list,l_idx+length(p_del)); else pipe row(l_list); exit; end if; end loop; return; end split; / 

Maintenant, vous pouvez utiliser une variable pour obtenir des valeurs dans une table:

 select * from table(split('one,two,three')) one two three select * from TABLE1 where COL1 in (select * from table(split('value1,value2'))) value1 AAA value2 BBB 

Ainsi, la déclaration préparée pourrait être:

  "select * from TABLE where COL in (select * from table(split(?)))" 

Cordialement,

Javier Ibanez

Voici comment je l’ai résolu dans ma propre application. Idéalement, vous devriez utiliser un SsortingngBuilder au lieu d’utiliser + pour les chaînes.

  Ssortingng inParenthesis = "(?"; for(int i = 1;i < myList.size();i++) { inParenthesis += ", ?"; } inParenthesis += ")"; try(PreparedStatement statement = SQLite.connection.prepareStatement( String.format("UPDATE table SET value='WINNER' WHERE startTime=? AND name=? AND traderIdx=? AND someValue IN %s", inParenthesis))) { int x = 1; statement.setLong(x++, race.startTime); statement.setString(x++, race.name); statement.setInt(x++, traderIdx); for(String str : race.betFair.winners) { statement.setString(x++, str); } int effected = statement.executeUpdate(); } 

Utiliser une variable comme x ci-dessus au lieu de nombres concrets aide beaucoup si vous décidez de modifier la requête ultérieurement.

Je suppose que vous pourriez (en utilisant la manipulation de chaîne de base) générer la chaîne de requête dans le PreparedStatement pour avoir un certain nombre de ? correspond au nombre d’éléments dans votre liste.

Bien sûr, si vous le faites, vous êtes à deux pas de générer un OR enchaîné géant dans votre requête, mais sans avoir le bon nombre de ? dans la chaîne de requête, je ne vois pas comment vous pouvez contourner cela.

Vous pouvez utiliser la méthode setArray comme mentionné dans ce javadoc :

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

essayez d’utiliser la fonction instr

 select my_column from my_table where instr(?, ','||search_column||',') > 0 

puis

 ps.setSsortingng(1, ",A,B,C,"); 

Certes, c’est un peu un bidouillage, mais cela réduit les possibilités d’injection de SQL. Fonctionne en oracle de toute façon.

Sormula prend en charge l’opérateur SQL IN en vous permettant de fournir un object java.util.Collection en tant que paramètre. Il crée une déclaration préparée avec un? pour chacun des éléments la collection. Voir l’ exemple 4 (SQL dans l’exemple est un commentaire pour clarifier ce qui est créé mais n’est pas utilisé par Sormula).

à la place d’utiliser

 SELECT my_column FROM my_table where search_column IN (?) 

utiliser l’instruction SQL comme

 select id, name from users where id in (?, ?, ?) 

et

 preparedStatement.setSsortingng( 1, 'A'); preparedStatement.setSsortingng( 2,'B'); preparedStatement.setSsortingng( 3, 'C'); 

ou utiliser une procédure stockée ce serait la meilleure solution, puisque les instructions SQL seront compilées et stockées dans le serveur DataBase

Je suis tombé sur un certain nombre de limitations liées à une déclaration préparée:

  1. Les instructions préparées ne sont mises en cache que dans la même session (Postgres), donc elles ne fonctionneront vraiment qu’avec le regroupement de connexions
  2. Un grand nombre d’instructions préparées différentes proposées par @BalusC peuvent entraîner une surcharge du cache et la suppression des instructions précédemment mises en cache
  3. La requête doit être optimisée et utiliser des indices. Cela semble évident, cependant, par exemple, la requête ANY (ARRAY …) proposée par @Boris dans l’une des meilleures réponses ne peut pas utiliser d’index et la requête sera lente malgré la mise en cache
  4. L’instruction préparée met également en cache le plan de requête et les valeurs réelles des parameters spécifiés dans l’instruction ne sont pas disponibles.

Parmi les solutions proposées, je choisirais celle qui ne diminue pas les performances des requêtes et rend le moins de requêtes possible. Ce sera le n ° 4 (regrouper quelques requêtes) à partir du lien @Don ou en spécifiant des valeurs NULL pour un «inutile»? marques telles que proposées par @Vladimir Dyuzhev

Voici une solution complète en Java pour créer la déclaration préparée pour vous:

 /*usage: Util u = new Util(500); //500 items per bracket. Ssortingng sqlBefore = "select * from myTable where ("; List values = new ArrayList(Arrays.asList(1,2,4,5)); ssortingng sqlAfter = ") and foo = 'bar'"; PreparedStatement ps = u.prepareStatements(sqlBefore, values, sqlAfter, connection, "someId"); */ import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; public class Util { private int numValuesInClause; public Util(int numValuesInClause) { super(); this.numValuesInClause = numValuesInClause; } public int getNumValuesInClause() { return numValuesInClause; } public void setNumValuesInClause(int numValuesInClause) { this.numValuesInClause = numValuesInClause; } /** Split a given list into a list of lists for the given size of numValuesInClause*/ public List> splitList( List values) { List> newList = new ArrayList>(); while (values.size() > numValuesInClause) { List sublist = values.subList(0,numValuesInClause); List values2 = values.subList(numValuesInClause, values.size()); values = values2; newList.add( sublist); } newList.add(values); return newList; } /** * Generates a series of split out in clause statements. * @param sqlBefore ""select * from dual where (" * @param values [1,2,3,4,5,6,7,8,9,10] * @param "sqlAfter ) and id = 5" * @return "select * from dual where (id in (1,2,3) or id in (4,5,6) or id in (7,8,9) or id in (10)" */ public Ssortingng genInClauseSql(Ssortingng sqlBefore, List values, Ssortingng sqlAfter, Ssortingng identifier) { List> newLists = splitList(values); Ssortingng stmt = sqlBefore; /* now generate the in clause for each list */ int j = 0; /* keep track of list:newLists index */ for (List list : newLists) { stmt = stmt + identifier +" in ("; SsortingngBuilder innerBuilder = new SsortingngBuilder(); for (int i = 0; i < list.size(); i++) { innerBuilder.append("?,"); } String inClause = innerBuilder.deleteCharAt( innerBuilder.length() - 1).toString(); stmt = stmt + inClause; stmt = stmt + ")"; if (++j < newLists.size()) { stmt = stmt + " OR "; } } stmt = stmt + sqlAfter; return stmt; } /** * Method to convert your SQL and a list of ID into a safe prepared * statements * * @throws SQLException */ public PreparedStatement prepareStatements(String sqlBefore, ArrayList values, Ssortingng sqlAfter, Connection c, Ssortingng identifier) throws SQLException { /* First split our potentially big list into lots of lists */ Ssortingng stmt = genInClauseSql(sqlBefore, values, sqlAfter, identifier); PreparedStatement ps = c.prepareStatement(stmt); int i = 1; for (int val : values) { ps.setInt(i++, val); } return ps; } } 

Spring permet de transmettre java.util.Lists à NamedParameterJdbcTemplate , qui automatise la génération de (?,?,?, …,?), En fonction du nombre d’arguments.

Pour Oracle, cette publication de blog traite de l’utilisation de oracle.sql.ARRAY (Connection.createArrayOf ne fonctionne pas avec Oracle). Pour cela, vous devez modifier votre instruction SQL:

 SELECT my_column FROM my_table where search_column IN (select COLUMN_VALUE from table(?)) 

La fonction de table oracle transforme le tableau transmis en une table comme la valeur utilisable dans l’instruction IN .

Juste pour être complet: Tant que l’ensemble des valeurs n’est pas trop grand, vous pouvez aussi simplement construire une instruction comme

 ... WHERE tab.col = ? OR tab.col = ? OR tab.col = ? 

que vous pouvez ensuite passer à prepare (), puis utilisez setXXX () dans une boucle pour définir toutes les valeurs. Cela semble décevant, mais de nombreux “gros” systèmes commerciaux font ce genre de choses jusqu’à ce qu’ils atteignent des limites spécifiques à la firebase database, par exemple 32 Ko (je pense que c’est le cas) pour les déclarations dans Oracle.

Bien sûr, vous devez vous assurer que l’ensemble ne sera jamais déraisonnablement grand, ou faire des erreurs lorsqu’il le sera.

Suivant l’idée de Adam. Faites en sorte que votre instruction préparée sélectionne my_column à partir de my_table où search_column dans (#) Créez une chaîne x et remplissez-la avec un nombre de “?,?,?” en fonction de votre liste de valeurs Puis modifiez simplement le # dans la requête pour votre nouvelle chaîne x un remplissage

Générez la chaîne de requête dans le PreparedStatement pour avoir un certain nombre de? Correspondant au nombre d’éléments de votre liste. Voici un exemple:

 public void myQuery(List items, int other) { ... Ssortingng q4in = generateQsForIn(items.size()); Ssortingng sql = "select * from stuff where foo in ( " + q4in + " ) and bar = ?"; PreparedStatement ps = connection.prepareStatement(sql); int i = 1; for (Ssortingng item : items) { ps.setSsortingng(i++, item); } ps.setInt(i++, other); ResultSet rs = ps.executeQuery(); ... } private Ssortingng generateQsForIn(int numQs) { Ssortingng items = ""; for (int i = 0; i < numQs; i++) { if (i != 0) items += ", "; items += "?"; } return items; } 

Il existe différentes approches alternatives que nous pouvons utiliser pour la clause IN dans PreparedStatement.

  1. Utilisation de requêtes simples – Performances les plus lentes et ressources importantes
  2. Utilisation de StoredProcedure – Plus rapide mais spécifique à la firebase database
  3. Créer une requête dynamic pour PreparedStatement – Good Performance mais ne bénéficie pas de la mise en cache et PreparedStatement est recompilé à chaque fois.
  4. Utilisez NULL dans les requêtes PreparedStatement – Performances optimales, fonctionne parfaitement lorsque vous connaissez la limite des arguments de la clause IN. S’il n’y a pas de limite, vous pouvez exécuter des requêtes en batch. Exemple de code est:

      int i = 1; for(; i <=ids.length; i++){ ps.setInt(i, ids[i-1]); } //set null for remaining ones for(; i<=PARAM_SIZE;i++){ ps.setNull(i, java.sql.Types.INTEGER); } 

Vous pouvez vérifier plus de détails sur ces approches alternatives ici .

Pour certaines situations, regexp pourrait aider. Voici un exemple que j’ai vérifié sur Oracle, et ça marche.

 select * from my_table where REGEXP_LIKE (search_column, 'value1|value2') 

Mais il y a un certain nombre d’inconvénients:

  1. Toute colonne appliquée doit être convertie en varchar / char, au moins implicitement.
  2. Besoin d’être prudent avec les caractères spéciaux.
  3. Cela peut ralentir les performances – dans mon cas, la version IN utilise l’parsing des index et des plages et la version de REGEXP effectue une parsing complète.

Après avoir examiné différentes solutions sur différents forums et ne pas trouver de solution, je pense que le piratage ci-dessous est le plus facile à suivre et à coder:

Exemple: Supposons que vous ayez plusieurs parameters à transmettre dans la clause ‘IN’. Il suffit de mettre une chaîne factice dans la clause ‘IN’, par exemple, “PARAM” indique la liste des parameters qui viendront à la place de cette chaîne factice.

  select * from TABLE_A where ATTR IN (PARAM); 

Vous pouvez collecter tous les parameters dans une seule variable Ssortingng dans votre code Java. Cela peut être fait comme suit:

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

Vous pouvez append tous vos parameters séparés par des virgules dans une seule variable de chaîne, “param1”, dans notre cas.

Après avoir collecté tous les parameters dans une seule chaîne, vous pouvez simplement remplacer le texte factice dans votre requête, à savoir “PARAM” dans ce cas, avec le paramètre Ssortingng, c’est-à-dire param1. Voici ce que tu dois faire:

  Ssortingng query = query.replaceFirst("PARAM",param1); where we have the value of query as query = "select * from TABLE_A where ATTR IN (PARAM)"; 

Vous pouvez maintenant exécuter votre requête en utilisant la méthode executeQuery (). Assurez-vous de ne pas avoir le mot “PARAM” dans votre requête. Vous pouvez utiliser une combinaison de caractères spéciaux et d’alphabets au lieu du mot “PARAM” afin de vous assurer qu’il n’ya aucune possibilité qu’un tel mot apparaisse dans la requête. J’espère que vous avez la solution.

Remarque: Bien que cette requête ne soit pas préparée, elle effectue le travail que je voulais pour mon code.

Juste pour être complet et parce que je n’ai vu personne d’autre le suggérer:

Avant d’implémenter l’une des suggestions compliquées ci-dessus, considérez si l’injection SQL est effectivement un problème dans votre scénario.

Dans de nombreux cas, la valeur fournie à IN (…) est une liste d’id qui ont été générés de manière à garantir qu’aucune injection n’est possible … (par exemple, les résultats d’une sélection précédente some_id de some_table où some_condition.)

Si tel est le cas, vous pouvez simplement concaténer cette valeur et ne pas utiliser les services ou l’instruction préparée pour cela ou les utiliser pour d’autres parameters de cette requête.

 query="select f1,f2 from t1 where f3=? and f2 in (" + sListOfIds + ");"; 

PreparedStatement ne fournit aucun moyen efficace de traiter la clause SQL IN. Selon http://www.javaranch.com/journal/200510/Journal200510.jsp#a2 “Vous ne pouvez pas remplacer les éléments destinés à faire partie de l’instruction SQL. Cela est nécessaire car si le SQL lui-même peut changer, le le pilote ne peut pas précomstackr la déclaration. Cela a également pour effet de prévenir les attaques par injection SQL. ” J’ai fini par utiliser l’approche suivante:

 Ssortingng query = "SELECT my_column FROM my_table where search_column IN ($searchColumns)"; query = query.replace("$searchColumns", "'A', 'B', 'C'"); Statement stmt = connection.createStatement(); boolean hasResults = stmt.execute(query); do { if (hasResults) return stmt.getResultSet(); hasResults = stmt.getMoreResults(); } while (hasResults || stmt.getUpdateCount() != -1); 

SetArray est la meilleure solution mais elle n’est pas disponible pour de nombreux pilotes plus anciens. La solution de contournement suivante peut être utilisée dans java8

 Ssortingng baseQuery ="SELECT my_column FROM my_table where search_column IN (%s)" Ssortingng markersSsortingng = inputArray.stream().map(e -> "?").collect(joining(",")); Ssortingng sqlQuery = Ssortingng.format(baseSQL, markersSsortingng); //Now create Prepared Statement and use loop to Set ensortinges int index=1; for (Ssortingng input : inputArray) { preparedStatement.setSsortingng(index++, input); } 

Cette solution est meilleure que d’autres solutions laides quand la chaîne de requête est construite par itérations manuelles

Vous pouvez utiliser Collections.nCopies pour générer une collection d’espaces réservés et les joindre à l’aide de Ssortingng.join :

 List params = getParams(); Ssortingng placeHolders = Ssortingng.join(",", Collections.nCopies(params.size(), "?")); Ssortingng sql = "select * from your_table where some_column in (" + placeHolders + ")"; try ( Connection connection = getConnection(); PreparedStatement ps = connection.prepareStatement(sql)) { int i = 1; for (Ssortingng param : params) { ps.setSsortingng(i++, param); } /* * Execute query/do stuff */ } 

My workaround (JavaScript)

  var s1 = " SELECT " + "FROM table t " + " where t.field in "; var s3 = '('; for(var i =0;i 

SearchTerms is the array which contains your input/keys/fields etc