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

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


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

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.


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;

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


11
Masalah dengan solusi ini adalah, bahwa konten di listeParamsForInClausetidak akan melarikan diri dan membuat Anda rentan terhadap injeksi SQL.
Malax
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.