Как эффективно выполнять запросы 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 (). Я хотел бы иметь что-то вроде подстановки параметров готовых операторов

Ответы:


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 ...).
зевать


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-инъекций.
Малакс
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.