Come eseguire le query SQL IN () con JDBCTemplate di Spring in modo efficace?


177

Mi chiedevo se esiste un modo più elegante per eseguire query IN () con JDBCTemplate di Spring. Attualmente faccio qualcosa del genere:

StringBuilder jobTypeInClauseBuilder = new StringBuilder();
for(int i = 0; i < jobTypes.length; i++) {
    Type jobType = jobTypes[i];

    if(i != 0) {
        jobTypeInClauseBuilder.append(',');
    }

    jobTypeInClauseBuilder.append(jobType.convert());
}

Il che è abbastanza doloroso dal momento che se ho nove righe solo per la creazione della clausola per la query IN (). Vorrei avere qualcosa di simile alla sostituzione dei parametri delle istruzioni preparate

Risposte:


275

Vuoi una fonte di parametri:

Set<Integer> ids = ...;

MapSqlParameterSource parameters = new MapSqlParameterSource();
parameters.addValue("ids", ids);

List<Foo> foo = getJdbcTemplate().query("SELECT * FROM foo WHERE a IN (:ids)",
     parameters, getRowMapper());

Funziona solo se getJdbcTemplate()restituisce un'istanza di tipoNamedParameterJdbcTemplate


5
Perfetto, il NamedParameterJdbcTemplate era esattamente quello che stavo cercando. Inoltre mi piacciono i parametri nominati più di quei punti interrogativi ovunque. Molte grazie!
Malax,

5
Funziona con elenchi di piccole dimensioni, ma il tentativo di utilizzarlo su un elenco di grandi dimensioni comporta una query in cui: ids viene sostituito con "?,?,?,?,? ......" e con elementi di elenco sufficienti trabocca. Esiste una soluzione che funziona per elenchi di grandi dimensioni?
sabato

Probabilmente dovresti inserire i valori in una tabella temporanea e creare la condizione usando WHERE NOT EXISTS (SELECT ...).
sbadiglio


9
strano, ottengo "codice errore [17004]; tipo di colonna non valido" quando provo questo.
Trevor,

61

Faccio la query "in clausola" con jdbc di primavera in questo modo:

String sql = "SELECT bg.goodsid FROM beiker_goods bg WHERE bg.goodsid IN (:goodsid)";

List ids = Arrays.asList(new Integer[]{12496,12497,12498,12499});
Map<String, List> paramMap = Collections.singletonMap("goodsid", ids);
NamedParameterJdbcTemplate template = 
    new NamedParameterJdbcTemplate(getJdbcTemplate().getDataSource());

List<Long> list = template.queryForList(sql, paramMap, Long.class);

10
Hai appena pubblicato una risposta a una domanda di quasi tre anni con la stessa soluzione della risposta accettata. C'è qualche buona ragione dietro questo? :-)
Malax,

16
Questa risposta fornisce più chiarezza perché dimostra che NamedParameterJdbcTemplate è necessario per questa API ... quindi grazie per il dettaglio aggiuntivo janwen
IcedDante

@janwen, grazie per la soluzione !!! Funziona bene secondo il mio requisito !!
Karthik Amarnath Saakre,

19

Se ricevi un'eccezione per: tipo di colonna non valido

Si prega di utilizzare getNamedParameterJdbcTemplate()invece digetJdbcTemplate()

 List<Foo> foo = getNamedParameterJdbcTemplate().query("SELECT * FROM foo WHERE a IN (:ids)",parameters,
 getRowMapper());

Si noti che i secondi due argomenti vengono scambiati.


2
Questa non sembra essere una risposta a questa domanda. Dovrebbe essere un commento su un'altra risposta?
Dave Schweisguth,

2
@DaveSchweisguth Due anni dopo, merita sicuramente una risposta.
dwjohnston,

2

Fare riferimento qui

scrivere query con parametro denominato, utilizzare simple ListPreparedStatementSettercon tutti i parametri in sequenza. Aggiungi lo snippet di seguito per convertire la query in forma tradizionale in base ai parametri disponibili,

ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(namedSql);

List<Integer> parameters = new ArrayList<Integer>();
for (A a : paramBeans)
    parameters.add(a.getId());

MapSqlParameterSource parameterSource = new MapSqlParameterSource();
parameterSource.addValue("placeholder1", parameters);
// create SQL with ?'s
String sql = NamedParameterUtils.substituteNamedParameters(parsedSql, parameterSource);     
return sql;

per me questa è stata l'unica risposta che ha funzionato poiché volevo solo impostare alcuni segnaposto
Kapil,

-4

Molte cose sono cambiate dal 2009, ma posso trovare solo risposte che dicono che è necessario utilizzare NamedParametersJDBCTemplate.

Per me funziona se faccio solo a

db.query(sql, new MyRowMapper(), StringUtils.join(listeParamsForInClause, ","));

utilizzando SimpleJDBCTemplate o JDBCTemplate


11
Il problema con questa soluzione è che il contenuto in listeParamsForInClausenon sarà evaso e ti renderà vulnerabile all'iniezione SQL.
Malax,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.