Bagaimana cara mengeksekusi IN () query SQL dengan Spring's JDBCTemplate secara efektif?

177

Saya bertanya-tanya apakah ada cara yang lebih elegan untuk melakukan IN () query dengan Spring's JDBCTemplate. Saat ini saya melakukan sesuatu seperti itu:

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

Yang cukup menyakitkan karena jika saya memiliki sembilan baris hanya untuk membangun klausa untuk permintaan IN (). Saya ingin memiliki sesuatu seperti substitusi parameter pernyataan yang disiapkan

Malax
sumber

Jawaban:

275

Anda menginginkan sumber parameter:

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

Ini hanya berfungsi jika getJdbcTemplate()mengembalikan turunan tipeNamedParameterJdbcTemplate

menguap
sumber
5
Sempurna, NamedParameterJdbcTemplate persis seperti yang saya cari. Selain itu saya suka parameter bernama lebih dari tanda tanya di semua tempat. Terima kasih banyak!
Malax
5
Ini berfungsi untuk daftar kecil, tetapi mencoba menggunakannya pada daftar besar menghasilkan kueri di mana: id diganti dengan "?,?,?,?,? ......" dan dengan item daftar yang cukup melimpah. Apakah ada solusi yang berfungsi untuk daftar besar?
nsayer
Anda mungkin harus memasukkan nilai-nilai ke dalam tabel sementara dan membangun kondisi menggunakan WHERE NOT EXISTS (SELECT ...).
menguap
6
Untuk melengkapi jawaban: Pegas 3.1 Referensi - Melewati daftar nilai untuk klausa IN . Tetapi dalam Referensi tidak ada yang dikatakan tentang: adalah mungkin untuk melewati Koleksi apa pun .
Timofey Gorshkov
9
aneh, saya mendapatkan "kode kesalahan [17004]; Jenis kolom tidak valid" ketika saya mencoba ini.
Trevor
61

Saya melakukan kueri "in clause" dengan spring jdbc seperti ini:

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);
Tuan Lou
sumber
10
Anda baru saja memposting jawaban untuk pertanyaan yang hampir tiga tahun dengan solusi yang sama dengan jawaban yang diterima. Apakah ada alasan bagus di balik ini? :-)
Malax
16
Jawaban ini memberikan lebih banyak kejelasan karena menggambarkan bahwa NamedParameterJdbcTemplate diperlukan untuk API ini ... jadi terima kasih untuk perincian tambahan janwen
IcedDante
@janwen, Terima kasih atas solusinya !!! Ini berfungsi dengan baik sesuai kebutuhan saya !!
Karthik Amarnath Saakre
19

Jika Anda mendapatkan pengecualian untuk: Jenis kolom tidak valid

Silakan gunakan getNamedParameterJdbcTemplate()sebagai gantigetJdbcTemplate()

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

Perhatikan bahwa dua argumen kedua ditukar.

Mahmood Omari
sumber
2
Ini sepertinya bukan jawaban untuk pertanyaan ini. Haruskah itu menjadi komentar atas jawaban lain?
Dave Schweisguth
2
@DaveSchweisguth Dua tahun kemudian, itu pasti menjadi jawaban.
dwjohnston
2

Lihat di sini

tulis kueri dengan parameter bernama, gunakan sederhana ListPreparedStatementSetterdengan semua parameter secara berurutan. Cukup tambahkan cuplikan di bawah ini untuk mengonversi kueri dalam bentuk tradisional berdasarkan parameter yang tersedia,

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;
Abhishek Chatterjee
sumber
bagi saya ini adalah satu-satunya jawaban yang berhasil karena saya hanya ingin menetapkan beberapa placeholder
Kapil
-4

Banyak hal berubah sejak 2009, tetapi saya hanya dapat menemukan jawaban yang mengatakan Anda perlu menggunakan NamedParametersJDBCTemplate.

Bagi saya itu berfungsi jika saya hanya melakukan a

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

menggunakan SimpleJDBCTemplate atau JDBCTemplate

luso
sumber
11
Masalah dengan solusi ini adalah, bahwa konten di listeParamsForInClausetidak akan melarikan diri dan membuat Anda rentan terhadap injeksi SQL.
Malax