วิธีการดำเนินการแบบสอบถาม IN () SQL ที่มี JDBCTemplate ของ Spring มีผลบังคับใช้อย่างไร


177

ฉันสงสัยว่ามีวิธีที่สง่างามกว่าในการทำคำสั่ง IN () กับ JDBCTemplate ของ Spring หรือไม่ ขณะนี้ฉันทำอะไรแบบนั้น:

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 เป็นสิ่งที่ฉันกำลังมองหา นอกจากนี้ฉันชอบพารามิเตอร์ที่มีชื่อมากกว่าคำถามเหล่านั้นทำเครื่องหมายทุกที่ ขอบคุณมาก!
Malax

5
สิ่งนี้ใช้ได้กับรายการขนาดเล็ก แต่การพยายามที่จะใช้กับรายการขนาดใหญ่จะส่งผลให้เกิดการสืบค้นโดยที่: ids ถูกแทนที่ด้วย "?,,,,,,,,, ...... " และมีรายการเพียงพอ มีวิธีแก้ปัญหาที่เหมาะกับรายการขนาดใหญ่หรือไม่?
nsayer

WHERE NOT EXISTS (SELECT ...)คุณอาจจะใส่ค่าลงในตารางชั่วคราวและสร้างเงื่อนไขที่ใช้
yawn

6
คำตอบ comlete: ฤดูใบไม้ผลิ 3.1 อ้างอิง - ผ่านในรายการของค่าสำหรับประโยคหนึ่งใน แต่ในการอ้างอิงได้รับการกล่าวเกี่ยวกับอะไร: มันเป็นไปได้ที่จะผ่านการเก็บใด
Timofey Gorshkov

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 ขอบคุณสำหรับการแก้ปัญหา !!! มันทำงานได้ดีตามความต้องการของฉัน !!
Karthik Amarnath Saakre

19

หากคุณได้รับข้อยกเว้นสำหรับ: ประเภทคอลัมน์ไม่ถูกต้อง

กรุณาใช้getNamedParameterJdbcTemplate()แทนgetJdbcTemplate()

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

โปรดทราบว่าข้อโต้แย้งที่สองจะถูกสลับไปมา


2
ดูเหมือนจะไม่ใช่คำตอบสำหรับคำถามนี้ ควรแสดงความคิดเห็นในคำตอบอื่นหรือไม่
Dave Schweisguth

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;

สำหรับฉันนี่เป็นคำตอบเดียวที่ทำงานได้เพราะฉันต้องการตั้งตัวแทนไม่กี่คน
Kapil

-4

หลายสิ่งเปลี่ยนไปตั้งแต่ปี 2009 แต่ฉันสามารถค้นหาคำตอบที่บอกว่าคุณต้องใช้ NamedParametersJDBCT

สำหรับฉันมันใช้งานได้ถ้าฉันเพิ่งทำ

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

ใช้ SimpleJDBCTemplate หรือ JDBCTemplate


11
ปัญหาเกี่ยวกับการแก้ปัญหานี้คือเนื้อหาที่listeParamsForInClauseจะไม่หนีและทำให้คุณเสี่ยงต่อการฉีด SQL
Malax
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.