स्प्रिंग के JDBCTemplate के साथ IN () SQL प्रश्नों को कैसे प्रभावी ढंग से निष्पादित किया जाए?


177

मैं सोच रहा था कि क्या वसंत के 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 () क्वेरी के लिए क्लॉज बनाने के लिए सिर्फ नौ लाइनें हैं। मैं तैयार बयानों के पैरामीटर प्रतिस्थापन की तरह कुछ करना चाहूंगा

जवाबों:


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
यह छोटी सूचियों के लिए काम करता है, लेकिन एक बड़ी सूची पर इसका उपयोग करने का प्रयास करता है, जिसमें क्वेरी: ids को "?, ?, ?,, ?,? ......?" के साथ प्रतिस्थापित किया जाता है और पर्याप्त सूची आइटमों के साथ इसे ओवरफ्लो कर देता है। क्या कोई समाधान है जो बड़ी सूचियों के लिए काम करता है?
nsayer

आपको शायद एक अस्थायी तालिका में मान सम्मिलित करना चाहिए और उपयोग करके स्थिति का निर्माण करना चाहिए WHERE NOT EXISTS (SELECT ...)
जम्हाई


9
अजीब है, मुझे "त्रुटि कोड [17004] मिलता है। जब मैं यह कोशिश करता हूं तो अमान्य कॉलम प्रकार"।
ट्रेवर

61

मैं वसंत खंड के साथ "क्लॉज" क्वेरी में इस तरह से करता हूं:

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
आपने अभी लगभग तीन साल पुराने प्रश्न का उत्तर उसी समाधान के साथ पोस्ट किया है, जैसा स्वीकृत उत्तर में था। क्या इसके पीछे कोई अच्छा कारण है? :-)
मालाक्स

16
यह उत्तर अधिक स्पष्टता प्रदान करता है क्योंकि यह दर्शाता है कि इस एपीआई के लिए NamedParameterJdbcTemplate की आवश्यकता है ... इसलिए अतिरिक्त विस्तार के लिए धन्यवाद jwen
IcedDante

@ भजन, समाधान के लिए धन्यवाद !!! यह मेरी आवश्यकता के अनुसार ठीक काम कर रहा है !!
कार्तिक अमरनाथ साकरे

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 इंजेक्शन के लिए असुरक्षित बना देती है।
Malax
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.