SpringのJDBCTemplateを使ってIN()SQLクエリを効果的に実行する方法は?


177

SpringのJDBCTemplateでIN()クエリを実行するよりエレガントな方法があるかどうか疑問に思いました。現在私はそのようなことをしています:

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()クエリの句を作成するためだけに9行ある場合、これは非常に苦痛です。準備されたステートメントのパラメーター置換のようなものが欲しい

回答:


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はまさに私が探していたものです。加えて、私は至る所にそれらの疑問符よりも名前付きパラメーターが好きです。どうもありがとう!
マラックス2009

5
これは小さなリストでも機能しますが、大きなリストで使用しようとすると、クエリが:idsが "?、?、?、?、?......"に置き換えられ、十分なリストアイテムでオーバーフローします。大きなリストで機能する解決策はありますか?
nsayer 2010

値を一時テーブルに挿入し、を使用して条件を構築する必要がありWHERE NOT EXISTS (SELECT ...)ます。
あくび

6
回答を完了するには:Spring 3.1リファレンス— IN句の値のリストを渡す。しかし、リファレンスでは何も言われていませんでした:任意のCollectionを渡すことが可能です。
Timofey Gorshkov 2012年

9
奇妙なことに、これを試すと「エラーコード[17004];無効な列タイプ」が表示されます。
Trevor

61

次のように、Spring 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
承認された回答と同じソリューションで、ほぼ3年前の質問に対する回答を投稿しました。この背後に何か正当な理由はありますか?:-)
Malax

16
この回答は、NamedParameterJdbcTemplateがこのAPIに必要であることを示しているため、より明確になります... janwen
IcedD​​ante

@janwen、ソリューションをありがとう!!! それは私の要件に従って正常に動作しています!!
Karthik Amarnath Saakre

19

例外が発生した場合:無効な列タイプ

getNamedParameterJdbcTemplate()代わりに使用してくださいgetJdbcTemplate()

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

2番目の2つの引数が入れ替わっていることに注意してください。


2
これはこの質問に対する答えではないようです。それは別の答えに対するコメントであるべきですか?
Dave Schweisguth 2014年

2
@DaveSchweisguth 2年後、間違いなく答えであることを保証します。
dwjohnston 2015

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;

私にとって、これは私がいくつかのプレースホルダーを設定したかっただけで機能した唯一の答えでした
Kapil

-4

2009年以降、多くの変更がありましたが、NamedParametersJDBCTemplateを使用する必要があるという答えしか見つかりません。

私にとっては、

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

SimpleJDBCTemplateまたはJDBCTemplateの使用


11
このソリューションの問題は、のコンテンツlisteParamsForInClauseがエスケープされず、SQLインジェクションに対して脆弱になることです。
Malax
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.