Как эффективно выполнять запросы IN () SQL с помощью Spring JDBCTemplate?

177

Мне было интересно, есть ли более элегантный способ выполнять запросы IN () с помощью Spring JDBCTemplate. В настоящее время я делаю что-то подобное:

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

Что довольно больно, так как, если у меня есть девять строк только для построения предложения для запроса IN (). Я хотел бы иметь что-то вроде подстановки параметров готовых операторов

Malax
источник

Ответы:

275

Вы хотите источник параметра:

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

Это работает только если getJdbcTemplate()возвращает экземпляр типаNamedParameterJdbcTemplate

зевать
источник
5
Отлично, NamedParameterJdbcTemplate был именно то, что я искал. Кроме того, мне нравятся именованные параметры больше, чем эти вопросительные знаки повсюду. Большое спасибо!
Малакс
5
Это работает для небольших списков, но попытка использовать его в большом списке приводит к запросу, где: идентификаторы заменяются на «?,?,?,?,? ......» и с достаточным количеством элементов списка, которые переполняются. Есть ли решение, которое работает для больших списков?
nsayer
Вам, вероятно, следует вставить значения во временную таблицу и построить условие, используя WHERE NOT EXISTS (SELECT ...).
зевать
6
Для ответа: Spring 3.1 Reference - Передача в списках значений для предложения IN . Но в справочнике ничего не сказано о: можно пропустить любую коллекцию .
Тимофей Горшков
9
странно, я получаю «код ошибки [17004]; неверный тип столбца», когда я пытаюсь это сделать.
Тревор
61

Я делаю запрос «в предложении» с пружиной jdbc следующим образом:

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
Вы только что опубликовали ответ на почти трехлетний вопрос с тем же решением, что и принятый ответ. Есть ли веская причина этого? :-)
Malax
16
Этот ответ дает больше ясности, потому что он иллюстрирует, что NamedParameterJdbcTemplate необходим для этого API ... так что спасибо за дополнительную информацию janwen
IcedDante
@janwen, спасибо за решение !!! Это работает нормально согласно моему требованию!
Картик Амарнатх Саакре
19

Если вы получаете исключение для: Неверный тип столбца

Пожалуйста, используйте getNamedParameterJdbcTemplate()вместоgetJdbcTemplate()

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

Обратите внимание, что вторые два аргумента меняются местами.

Махмуд Омари
источник
2
Это не похоже на ответ на этот вопрос. Должен ли это быть комментарий к другому ответу?
Дейв Швейсгут
2
@DaveSchweisguth Два года спустя, это определенно гарантирует ответ.
dwjohnston
2

Обратитесь сюда

написать запрос с именованным параметром, использовать простой ListPreparedStatementSetterсо всеми параметрами в последовательности. Просто добавьте ниже фрагмент кода, чтобы преобразовать запрос в традиционной форме на основе доступных параметров,

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;
Абхишек Чаттерджи
источник
для меня это был единственный ответ, который сработал, так как я просто хотел установить несколько заполнителей
Капил
-4

С 2009 года многое изменилось, но я могу только найти ответы о том, что вам нужно использовать NamedParametersJDBCTemplate.

Для меня это работает, если я просто делаю

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

используя SimpleJDBCTemplate или JDBCTemplate

португало
источник
11
Проблема с этим решением состоит в том, что содержимое не listeParamsForInClauseможет быть экранировано и делает вас уязвимыми для SQL-инъекций.
Малакс