Como executar consultas SQL IN () com JDBCTemplate do Spring efetivamente?


177

Eu queria saber se existe uma maneira mais elegante de fazer consultas IN () com o JDBCTemplate do Spring. Atualmente eu faço algo assim:

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());
}

O que é bastante doloroso, pois se eu tiver nove linhas apenas para criar a cláusula para a consulta IN (). Eu gostaria de ter algo como a substituição de parâmetro de instruções preparadas

Respostas:


275

Você deseja uma fonte de parâmetro:

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());

Isso funciona apenas se getJdbcTemplate()retornar uma instância do tipoNamedParameterJdbcTemplate


5
Perfeito, o NamedParameterJdbcTemplate era exatamente o que eu estava procurando. Além disso, eu gosto de parâmetros nomeados mais do que esses pontos de interrogação em todo o lugar. Muito obrigado!
Malax 25/08

5
Isso funciona para listas pequenas, mas a tentativa de usá-lo em uma lista grande resulta em uma consulta na qual: ids é substituída por "?,?,?,?,? ......" e com itens de lista suficientes, ela transborda. Existe uma solução que funcione para grandes listas?
Nsayer

Você provavelmente deve inserir os valores em uma tabela temporária e criar a condição usando WHERE NOT EXISTS (SELECT ...).
bocejo 26/05


9
estranho, recebo "código de erro [17004]; tipo de coluna inválido" quando tento isso.
quer

61

Eu faço a consulta "na cláusula" com o jdbc do spring assim:

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
Você acabou de postar uma resposta para uma pergunta de quase três anos com a mesma solução que a resposta aceita. Existe alguma boa razão por trás disso? :-)
Malax

16
Esta resposta fornece mais clareza porque ilustra que o NamedParameterJdbcTemplate é necessário para esta API ... então obrigado pela janwen detalhes adicionais
IcedDante

@janwen, Obrigado pela solução !!! Está funcionando bem conforme minha exigência !!
Karthik Amarnath Saakre

19

Se você receber uma exceção para: Tipo de coluna inválido

Por favor use em getNamedParameterJdbcTemplate()vez degetJdbcTemplate()

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

Observe que os dois segundos argumentos são trocados.


2
Isso não parece ser uma resposta para esta pergunta. Deveria ser um comentário sobre outra resposta?
Dave Schweisguth

2
@DaveSchweisguth Dois anos depois, definitivamente merece ser uma resposta.
precisa saber é o seguinte

2

Consulte aqui

escrever consulta com parâmetro nomeado, use simple ListPreparedStatementSettercom todos os parâmetros em sequência. Basta adicionar o snippet abaixo para converter a consulta no formato tradicional com base nos parâmetros disponíveis,

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;

para mim, esta foi a única resposta que funcionou, pois eu só queria definir alguns espaços reservados
Kapil 24/01

-4

Muitas coisas mudaram desde 2009, mas só consigo encontrar respostas dizendo que você precisa usar o NamedParametersJDBCTemplate.

Para mim, funciona se eu apenas fizer uma

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

usando SimpleJDBCTemplate ou JDBCTemplate


11
O problema com esta solução é que o conteúdo listeParamsForInClausenão será escapado e o tornará vulnerável à injeção de SQL.
Malax
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.