तैयार विकल्प खंड विकल्प में?


343

INउदाहरणों के साथ SQL क्लॉज़ का उपयोग करने के लिए सबसे अच्छा वर्कअराउंड क्या हैं java.sql.PreparedStatement, जो SQL इंजेक्शन अटैक सुरक्षा समस्याओं के कारण कई मानों के लिए समर्थित नहीं है: एक ?प्लेसहोल्डर मानों की सूची के बजाय एक मान का प्रतिनिधित्व करता है।

निम्नलिखित SQL कथन पर विचार करें:

SELECT my_column FROM my_table where search_column IN (?)

उपयोग करना preparedStatement.setString( 1, "'A', 'B', 'C'" );अनिवार्य रूप ?से पहली जगह में उपयोग करने के कारणों के वर्कअराउंड में एक गैर-काम करने का प्रयास है।

क्या वर्कअराउंड उपलब्ध हैं?


1
ऑस्कर, मुझे लगता है कि (?;; .... ....) की गतिशील पीढ़ी को अगर आपको एक IN क्लॉज की जरूरत है तो सबसे सरल वर्कअराउंड है, लेकिन मैंने इसे व्यक्तिगत कॉल पर छोड़ दिया क्योंकि मेरे विशिष्ट मामले में प्रदर्शन पर्याप्त था।
क्रिस माजोला

6
तैयार किए गए कथनों में से एक लाभ यह है कि दक्षता के लिए सोहुलड को एक बार संकलित किया जा सकता है। क्लॉज को डायनामिक बनाने से यह प्रभावी रूप से तैयार स्टेटमेंट को नकारता है।

2
दरअसल, यह MySQL के लिए काम करता है (पैरामीटर मान के रूप में स्ट्रिंग की एक सरणी सेट करने के लिए setObject का उपयोग करके)। आप किस DB का उपयोग कर रहे हैं?
फ्राँस


यहाँ एक संबंधित प्रश्न है: stackoverflow.com/q/6956025/521799
लुकास ईडर

जवाबों:


194

उपलब्ध विभिन्न विकल्पों का विश्लेषण, और प्रत्येक के पेशेवरों और विपक्ष यहां उपलब्ध है

सुझाए गए विकल्प हैं:

  • तैयार करें SELECT my_column FROM my_table WHERE search_column = ?, प्रत्येक मूल्य के लिए इसे निष्पादित करें और परिणाम क्लाइंट-साइड को यूनिअन करें। केवल एक तैयार कथन की आवश्यकता है। धीमा और दर्दनाक।
  • तैयार SELECT my_column FROM my_table WHERE search_column IN (?,?,?)इसे और निष्पादित । आकार-में-सूची के अनुसार एक तैयार विवरण की आवश्यकता है। तेज और स्पष्ट।
  • SELECT my_column FROM my_table WHERE search_column = ? ; SELECT my_column FROM my_table WHERE search_column = ? ; ...इसे तैयार करें और निष्पादित करें । [या UNION ALLउन अर्धविरामों के स्थान पर उपयोग करें । --ed] को आकार-में-सूची के अनुसार एक तैयार विवरण की आवश्यकता होती है। मूर्खतापूर्ण रूप से धीमा, सख्ती से भी बदतर है WHERE search_column IN (?,?,?), इसलिए मुझे नहीं पता कि ब्लॉगर ने इसका सुझाव क्यों दिया।
  • परिणाम सेट के निर्माण के लिए एक संग्रहीत प्रक्रिया का उपयोग करें।
  • एन-एन-साइज़-इन-लिस्ट क्वेरी तैयार करें; 2, 10 और 50 मानों के साथ। 6 अलग-अलग मानों के साथ एक इन-सूची की खोज करने के लिए, आकार -10 क्वेरी को पॉप्युलेट करें ताकि यह जैसा दिखता है SELECT my_column FROM my_table WHERE search_column IN (1,2,3,4,5,6,6,6,6,6)। कोई भी सभ्य सर्वर क्वेरी चलाने से पहले डुप्लिकेट मानों का अनुकूलन करेगा।

इन विकल्पों में से कोई भी सुपर महान नहीं है, हालांकि।

इन स्थानों पर डुप्लिकेट प्रश्नों के उत्तर समान रूप से दिए गए हैं, फिर भी उनमें से कोई भी महान नहीं है:

सही उत्तर, यदि आप JDBC4 का उपयोग कर रहे हैं और एक सर्वर जो समर्थन करता है x = ANY(y), PreparedStatement.setArrayयहाँ वर्णित अनुसार उपयोग करना है:

setArrayयद्यपि इन-सूचियों के साथ काम करने का कोई तरीका प्रतीत नहीं होता है , हालांकि।


कभी-कभी SQL स्टेटमेंट रनटाइम पर लोड किए जाते हैं (उदाहरण के लिए, एक गुण फ़ाइल से) लेकिन मापदंडों की एक चर संख्या की आवश्यकता होती है। ऐसे मामलों में, पहले क्वेरी को परिभाषित करें:

query=SELECT * FROM table t WHERE t.column IN (?)

अगला, क्वेरी लोड करें। फिर इसे चलाने से पहले मापदंडों की संख्या निर्धारित करें। पैरामीटर गणना ज्ञात होने के बाद, चलाएं:

sql = any( sql, count );

उदाहरण के लिए:

/**
 * Converts a SQL statement containing exactly one IN clause to an IN clause
 * using multiple comma-delimited parameters.
 *
 * @param sql The SQL statement string with one IN clause.
 * @param params The number of parameters the SQL statement requires.
 * @return The SQL statement with (?) replaced with multiple parameter
 * placeholders.
 */
public static String any(String sql, final int params) {
    // Create a comma-delimited list based on the number of parameters.
    final StringBuilder sb = new StringBuilder(
            new String(new char[params]).replace("\0", "?,")
    );

    // Remove trailing comma.
    sb.setLength(Math.max(sb.length() - 1, 0));

    // For more than 1 parameter, replace the single parameter with
    // multiple parameter placeholders.
    if (sb.length() > 1) {
        sql = sql.replace("(?)", "(" + sb + ")");
    }

    // Return the modified comma-delimited list of parameters.
    return sql;
}

कुछ डेटाबेस के लिए जहां JDBC 4 विनिर्देशन के माध्यम से एक सरणी गुजरती है, असमर्थित है, यह विधि धीमी गति से चलने वाली क्लॉज स्थिति = ?में बदलने की सुविधा प्रदान कर IN (?)सकती है, जिसे बाद में कॉल करके anyविधि का विस्तार किया जा सकता है ।


123

PostgreSQL के लिए समाधान:

final PreparedStatement statement = connection.prepareStatement(
        "SELECT my_column FROM my_table where search_column = ANY (?)"
);
final String[] values = getValues();
statement.setArray(1, connection.createArrayOf("text", values));
final ResultSet rs = statement.executeQuery();
try {
    while(rs.next()) {
        // do some...
    }
} finally {
    rs.close();
}

या

final PreparedStatement statement = connection.prepareStatement(
        "SELECT my_column FROM my_table " + 
        "where search_column IN (SELECT * FROM unnest(?))"
);
final String[] values = getValues();
statement.setArray(1, connection.createArrayOf("text", values));
final ResultSet rs = statement.executeQuery();
try {
    while(rs.next()) {
        // do some...
    }
} finally {
    rs.close();
}

1
अच्छा लग रहा है। इस कोड का कौन सा भाग PostreSQL विशिष्ट है? "जहां search_column = any (?)" या connection.createArrayOf? या कुछ और?
डेविड पोर्टेबेला

1
मुझे लगता है कि यह PostgreSQL- विशिष्ट की तुलना में अधिक JDBC4- विशिष्ट है, .createArrayOf()भाग के कारण, लेकिन मुझे यकीन नहीं है कि उपयोगकर्ता के लिए सख्त शब्दार्थ ArrayJDBC विनिर्देश द्वारा परिभाषित हैं।
लवेला

3
यदि .createArrayOfकाम नहीं करता है, तो आप सरणी शाब्दिक की अपनी स्वयं की मैनुअल रचना कर सकते हैं जैसे String arrayLiteral = "{A,\"B \", C,D}" (ध्यान दें कि "बी" में सी है जबकि सी नहीं है) और फिर statement.setString(1,arrayLiteral)जहां तैयार बयान है ... IN (SELECT UNNEST(?::VARCHAR[]))या ... IN (SELECT UNNEST(CAST(? AS VARCHAR[])))। (पुनश्च: मुझे नहीं लगता कि ANYएक के साथ काम करता है SELECT।)
ADTC

महान समाधान! सचमुच मेरे लिए दिन बचा लिया। पूर्णांक सरणी के लिए मैंने createArrayOf () के पहले पैरामीटर में "int" का उपयोग किया और यह अच्छा लग रहा है। हालांकि यह पहला पैरामीटर डीबी-विशिष्ट प्रतीत होता है, हालांकि प्रलेखन के आधार पर।
Emmanuel Touzery

2
यह सबसे साफ समाधान लगता है। अगर किसी को एचएसक्यूएलडीबी विशिष्ट सिंटैक्स की तलाश है: मैं इसे (UNNEST (?))
aureianimus

19

कोई आसान तरीका नहीं AFAIK। यदि लक्ष्य स्टेटमेंट कैश अनुपात को उच्च रखना है (यानी प्रति पैरामीटर गणना के अनुसार स्टेटमेंट नहीं बनाने के लिए), तो आप निम्न कार्य कर सकते हैं:

  1. कुछ (जैसे 10) मापदंडों के साथ एक बयान बनाएँ:

    ... कहाँ एक? (?, ?, ?, ?, ?, ?, ?, ?, ?,?)? ... ...

  2. सभी बीमांकिक मापदंडों को बांधें

    setString (1, "foo"); setString (2, "बार");

  3. बाकी को NULL के रूप में बांधें

    setNull (3, Types.VARCHAR) ... setNull (10, Types.VARCHAR)

NULL कभी भी किसी चीज से मेल नहीं खाता है, इसलिए यह SQL प्लान बिल्डर द्वारा अनुकूलित हो जाता है।

जब आप किसी DAO फ़ंक्शन में सूची पास करते हैं तो तर्क को स्वचालित करना आसान होता है:

while( i < param.size() ) {
  ps.setString(i+1,param.get(i));
  i++;
}

while( i < MAX_PARAMS ) {
  ps.setNull(i+1,Types.VARCHAR);
  i++;
}

"NULL कभी किसी चीज़ से मेल नहीं खाता" - क्या NULLक्वेरी NULLडेटाबेस में किसी मान से मेल खाएगी ?
क्रेग मैकक्यून

5
@CraigMcQueen नहीं यह नहीं होगा। ANSI मानक के अनुसार नल भी शून्य से मेल नहीं खाता है।
दाऊद इब्न करीम

आप IS NULL कीवर्ड का उपयोग करके NULL का मिलान कर सकते हैं। पंक्तियों का पता लगाने का एक अच्छा तरीका है जो कि शामिल तालिका में मौजूद नहीं है, IS NULL के साथ एक साथ LEFT JOIN का उपयोग करना है। 'SELECT a.URL, b.URL FROM TABLE_A एक LEFT JOIN TABLE_B b ऑन a_A.URL = b_B.URL जहां b.URL IS NULL' है। यह तालिका ए में उन सभी पंक्तियों को दिखाएगा जिनका तालिका बी में कोई मेल नहीं है
जेन्स टैंडस्टैड

3
हालांकि इसके साथ सावधान रहें। NOT INऔर INउसी तरह अशक्त संभाल नहीं है। इसे चलाएं और देखें कि क्या होता है: select 'Matched' as did_it_match where 1 not in (5, null); फिर nullजादू को हटा दें और देखें।
ब्रैंडन

या आप किसी भी पिछले परम के मूल्य में सभी अतिरिक्त पैरामेट्स सेट कर सकते हैं। कोई भी अच्छा DB इंजन उन्हें फ़िल्टर करेगा। तो a IN (1,2,3,3,3,3,3)जैसा है वैसा ही है a IN (1,2,3)। यह NOT INविपरीत के साथ भी काम करता है a NOT IN (1,2,3,null,null,null,null)(जो हमेशा कोई भी पंक्ति नहीं देता है जैसा any_value != NULLकि हमेशा गलत होता है)।
रुस्लान

11

एक अप्रिय काम के आसपास, लेकिन निश्चित रूप से एक नेस्टेड क्वेरी का उपयोग करने के लिए संभव है। इसमें एक कॉलम के साथ एक अस्थायी तालिका MYVALUES बनाएं। अपने मूल्यों की सूची MYVALUES तालिका में डालें। फिर अमल करें

select my_column from my_table where search_column in ( SELECT value FROM MYVALUES )

बदसूरत, लेकिन एक व्यवहार्य विकल्प यदि आपके मूल्यों की सूची बहुत बड़ी है।

इस तकनीक में ऑप्टिमाइज़र से संभावित बेहतर क्वेरी योजनाओं का अतिरिक्त लाभ है (कई मानों के लिए एक पृष्ठ की जांच करें, मूल्य के अनुसार एक बार केवल एक बार टेबलस्कैन, आदि) ओवरहेड पर सहेज सकते हैं यदि आपका डेटाबेस तैयार किए गए बयानों को कैश नहीं करता है। आपके "INSERTS" को बैच में करने की आवश्यकता होगी और MYVALUES तालिका को न्यूनतम लॉकिंग या अन्य उच्च-ओवरहेड सुरक्षा के लिए ट्वीक करने की आवश्यकता हो सकती है।


एक बार में my_table एक मान को ओवर करने से क्या फायदे होंगे?
पॉल टॉम्बलिन

3
क्वेरी ऑप्टिमाइज़र लोड पेज से सभी संभावित मैचों को पुनः प्राप्त करके I / O लोड को कम कर सकता है। मूल्य के अनुसार एक बार के बजाय एक बार टेबल्स या इंडेक्स स्कैन किए जा सकते हैं। मान डालने के लिए ओवरहेड को बैच संचालन के साथ कम किया जा सकता है और कई प्रश्नों से कम हो सकता है।
जेम्स स्कैच

1
यह अच्छा लग रहा है, लेकिन समस्या के साथ समस्या हो सकती है। क्या jdbc विनिर्देश में मेमोरी में एक अस्थायी अनाम तालिका बनाने का एक तरीका है? या ऐसा कुछ, अगर संभव नहीं तो jdbc- विक्रेता विशिष्ट?
डेविड पोर्टेबेला

9

() ऑपरेटर की सीमाएं सभी बुराई की जड़ हैं।

यह तुच्छ मामलों के लिए काम करता है, और आप इसे "तैयार विवरण की स्वचालित पीढ़ी" के साथ बढ़ा सकते हैं, हालांकि यह हमेशा अपनी सीमाएं रखता है।

  • यदि आप मापदंडों की चर संख्या के साथ एक बयान बना रहे हैं, तो यह प्रत्येक कॉल पर एक वर्ग पार्स ओवरहेड बना देगा
  • कई प्लेटफार्मों पर, () ऑपरेटर के मापदंडों की संख्या सीमित है
  • सभी प्लेटफार्मों पर, कुल एसक्यूएल पाठ का आकार सीमित है, जिससे पार्म्स के लिए 2000 प्लेसहोल्डर्स को भेजना असंभव है
  • 1000-10k के बिंदू वेरिएबल्स भेजना संभव नहीं है, क्योंकि JDBC ड्राइवर की सीमाएँ हैं

() दृष्टिकोण कुछ मामलों के लिए पर्याप्त हो सकता है, लेकिन रॉकेट प्रूफ नहीं :)

रॉकेट-प्रूफ समाधान एक अलग कॉल में पैरामीटर्स की मनमानी संख्या को पास करने के लिए है (उदाहरण के लिए पैराम का एक क्लोब पास करके), और फिर एसक्यूएल में उनका प्रतिनिधित्व करने और अपने में उपयोग करने के लिए एक दृश्य (या कोई अन्य तरीका) है। मानदंड।

एक जानवर बल संस्करण यहाँ है http://tkyte.blogspot.hu/2006/06/varying-in.list.html

हालाँकि यदि आप पीएल / एसक्यूएल का उपयोग कर सकते हैं, तो यह गड़बड़ हो सकती है।

function getCustomers(in_customerIdList clob) return sys_refcursor is 
begin
    aux_in_list.parse(in_customerIdList);
    open res for
        select * 
        from   customer c,
               in_list v
        where  c.customer_id=v.token;
    return res;
end;

फिर आप पैरामीटर में कॉमा से अलग किए गए ग्राहक आईडी की मनमानी संख्या पास कर सकते हैं, और:

  • कोई पार्स विलंब नहीं मिलेगा, क्योंकि चयन के लिए SQL स्थिर है
  • कोई पाइपलाइन कार्य जटिलता नहीं है - यह सिर्फ एक क्वेरी है
  • SQL एक IN ऑपरेटर के बजाय एक साधारण जॉइन का उपयोग कर रहा है, जो काफी तेज है
  • आखिरकार, किसी भी सादे चयन या डीएमएल के साथ डेटाबेस को नहीं मारना अंगूठे का एक अच्छा नियम है , क्योंकि यह ओरेकल है, जो MySQL या इसी तरह के सरल डेटाबेस इंजनों से अधिक की लाइटयर्स प्रदान करता है। PL / SQL आपको एक प्रभावी तरीके से अपने एप्लिकेशन डोमेन मॉडल से स्टोरेज मॉडल को छिपाने की अनुमति देता है।

यहाँ चाल है:

  • हमें एक कॉल की आवश्यकता होती है, जो लंबी स्ट्रिंग को स्वीकार करता है, और कहीं स्टोर करता है जहां db सत्र इसे एक्सेस कर सकता है (उदाहरण के लिए साधारण पैकेज चर, या dbms_session.set_context)
  • फिर हमें एक ऐसे दृश्य की आवश्यकता है जो इसे पंक्तियों तक पहुंचा सके
  • और फिर आपके पास एक ऐसा दृश्य है जिसमें आपके द्वारा क्वेरी किए जा रहे आईडी शामिल हैं, इसलिए आपको जो कुछ भी चाहिए वह एक सरल तालिका में सम्मिलित है।

देखने में ऐसा लगता है:

create or replace view in_list
as
select
    trim( substr (txt,
          instr (txt, ',', 1, level  ) + 1,
          instr (txt, ',', 1, level+1)
             - instr (txt, ',', 1, level) -1 ) ) as token
    from (select ','||aux_in_list.getpayload||',' txt from dual)
connect by level <= length(aux_in_list.getpayload)-length(replace(aux_in_list.getpayload,',',''))+1

जहाँ aux_in_list.getpayload मूल इनपुट स्ट्रिंग को संदर्भित करता है।


एक संभावित दृष्टिकोण pl / sql सरणियों (केवल Oracle द्वारा समर्थित) को पारित करने के लिए होगा, हालांकि आप शुद्ध SQL में उन का उपयोग नहीं कर सकते हैं, इसलिए रूपांतरण चरण की हमेशा आवश्यकता होती है। रूपांतरण SQL में नहीं किया जा सकता है, इसलिए सब के बाद, स्ट्रिंग में सभी मापदंडों के साथ एक क्लोब को पास करना और इसे एक दृश्य में परिवर्तित करना सबसे कुशल समाधान है।


6

यहां बताया गया है कि मैंने इसे अपने आवेदन में कैसे हल किया। आदर्श रूप से, आपको स्ट्रिंग्स के लिए + का उपयोग करने के बजाय एक स्ट्रिंगब्यूलर का उपयोग करना चाहिए।

    String inParenthesis = "(?";
    for(int i = 1;i < myList.size();i++) {
      inParenthesis += ", ?";
    }
    inParenthesis += ")";

    try(PreparedStatement statement = SQLite.connection.prepareStatement(
        String.format("UPDATE table SET value='WINNER' WHERE startTime=? AND name=? AND traderIdx=? AND someValue IN %s", inParenthesis))) {
      int x = 1;
      statement.setLong(x++, race.startTime);
      statement.setString(x++, race.name);
      statement.setInt(x++, traderIdx);

      for(String str : race.betFair.winners) {
        statement.setString(x++, str);
      }

      int effected = statement.executeUpdate();
    }

यदि आप बाद के समय में क्वेरी को बदलने का निर्णय लेते हैं, तो ठोस संख्याओं के बजाय x जैसे चर का उपयोग करने से बहुत मदद मिलती है।


5

मैंने कभी इसकी कोशिश नहीं की है, लेकिन .setArray () क्या आप देख रहे हैं?

अपडेट : जाहिर तौर पर नहीं। setArray केवल एक java.sql के साथ काम करने लगता है। उस ARRAY कॉलम से आता है जिसे आपने पिछली क्वेरी से पुनर्प्राप्त किया है, या ARRAY कॉलम के साथ एक उपश्रेणी।


4
सभी डेटाबेस के साथ काम नहीं करता है, लेकिन यह "सही" दृष्टिकोण है।
स्केफमैन

आप सभी ड्राइवरों का मतलब है। कुछ ड्राइवरों के पास इस वर्ष पुराने (पिछली शताब्दी?) मानक के मालिकाना समकक्ष हैं। एक और तरीका यह है कि एक अस्थायी तालिका में मूल्यों के एक बैच को
बांध दिया जाए

java.sun.com/j2se/1.3/docs/guide/jdbc/getstart/… सूर्य के अनुसार, एरियर सामग्री [आम तौर पर] सर्वर साइड पर रहती है और आवश्यकतानुसार खींची जाती है। ReadyedStatement.setArray () पिछले ResultSet से एक Array वापस भेज सकता है, क्लाइंट पक्ष पर एक नया Array नहीं बना सकता।
क्रिस माजोला

5

मेरा समाधान है:

create or replace type split_tbl as table of varchar(32767);
/

create or replace function split
(
  p_list varchar2,
  p_del varchar2 := ','
) return split_tbl pipelined
is
  l_idx    pls_integer;
  l_list    varchar2(32767) := p_list;
  l_value    varchar2(32767);
begin
  loop
    l_idx := instr(l_list,p_del);
    if l_idx > 0 then
      pipe row(substr(l_list,1,l_idx-1));
      l_list := substr(l_list,l_idx+length(p_del));
    else
      pipe row(l_list);
      exit;
    end if;
  end loop;
  return;
end split;
/

अब आप तालिका में कुछ मान प्राप्त करने के लिए एक चर का उपयोग कर सकते हैं:

select * from table(split('one,two,three'))
  one
  two
  three

select * from TABLE1 where COL1 in (select * from table(split('value1,value2')))
  value1 AAA
  value2 BBB

तो, तैयार बयान हो सकता है:

  "select * from TABLE where COL in (select * from table(split(?)))"

सादर,

जेवियर इबनेज़


यह PL / SQL है, हाँ। यह अन्य डेटाबेस में काम नहीं करता है। ध्यान दें कि इस कार्यान्वयन में इनपुट पैरामेट्स की एक सीमा है - कुल लंबाई 32k वर्णों तक सीमित है - और साथ ही पाइपलाइन फ़ंक्शन के लिए कॉल के बाद से एक प्रदर्शन सीमा, Oracle के PL / SQL और SQL इंजन के बीच एक संदर्भ स्विच करता है।
जी बी

3

मैं तुम्हें में (मूल स्ट्रिंग परिवर्तन का प्रयोग करके) कर सकता है उत्पन्न क्वेरी स्ट्रिंग लगता है PreparedStatementकी एक संख्या है करने के लिए ?की अपनी सूची में आइटम्स की संख्या मिलान।

यदि आप ऐसा कर रहे हैं, तो आप ORअपनी क्वेरी में जंजीर को पैदा करने से बस एक कदम दूर हैं , लेकिन ?क्वेरी स्ट्रिंग में सही संख्या न होने के बावजूद , मैं यह नहीं देखता कि आप इसके आसपास कैसे काम कर सकते हैं।


वास्तव में मेरे लिए कोई समाधान नहीं है क्योंकि मैं अलग संख्या में भेजना चाहता हूं? हर बार मैं पीएस कहता हूं। लेकिन मुझे नहीं लगता कि मैंने इस पर विचार नहीं किया था। : पी
क्रिस माज़ोला

4
एक और हैक: आप बड़ी संख्या में पैरामीटर प्लेसहोल्डर का उपयोग कर सकते हैं - जितने मानों की सबसे लंबी सूची आपके पास होगी - और यदि आपके मूल्यों की सूची छोटी है, तो आप मूल्यों को दोहरा सकते हैं: ... खोज क्षेत्र में (? ,?,?,?,?,?,?,?), और उसके बाद मान प्रदान करते हैं: ए, बी, सी, डी, ए, बी, सी, डी
बिल कार्विन

1
लेकिन कुल मिलाकर मैं एडम के समाधान का पक्ष लेता हूं: एसक्यूएल को गतिशील रूप से उत्पन्न करें, और संक्षिप्त करें? प्लेसहोल्डर्स को आपके द्वारा पास किए जाने वाले मानों की संख्या से मिलान करना है।
बिल कार्विन

यदि मैं रेडीस्टेयमेंट का पुन: उपयोग नहीं करना चाहता तो बिल, वह समाधान उपयोगी है। एक अन्य उपाय यह है कि सिंगल परम को कई बार कॉल किया जाए और क्लाइंट की तरफ से रिजल्ट जमा किया जाए। संभवतः कस्टम संख्या के साथ एक नया स्टेटमेंट बनाने / निष्पादित करने के लिए यह अधिक कुशल होगा? हालांकि हर बार।
क्रिस माज़ोला

3

आप इस javadoc में बताए अनुसार setArray विधि का उपयोग कर सकते हैं :

PreparedStatement statement = connection.prepareStatement("Select * from emp where field in (?)");
Array array = statement.getConnection().createArrayOf("VARCHAR", new Object[]{"E1", "E2","E3"});
statement.setArray(1, array);
ResultSet rs = statement.executeQuery();

2
यह सभी ड्राइवरों द्वारा समर्थित नहीं है, यदि सुविधा समर्थित नहीं है, तो आपको SQLFeatureNotSupportedException मिल जाएगी
अनाम

दुर्भाग्य से मेरा ड्राइवर इसका समर्थन नहीं करता है
EdXX

3

आप Collections.nCopiesप्लेसहोल्डर्स का एक संग्रह उत्पन्न करने और उनका उपयोग करने में शामिल होने के लिए उपयोग कर सकते हैं String.join:

List<String> params = getParams();
String placeHolders = String.join(",", Collections.nCopies(params.size(), "?"));
String sql = "select * from your_table where some_column in (" + placeHolders + ")";
try (   Connection connection = getConnection();
        PreparedStatement ps = connection.prepareStatement(sql)) {
    int i = 1;
    for (String param : params) {
        ps.setString(i++, param);
    }
    /*
     * Execute query/do stuff
     */
}

Oracle JDBC का उपयोग करते समय अब ​​तक का सबसे अच्छा उपाय लगता है ...
jsosohn

2

आपके लिए तैयार स्टेटमेंट बनाने के लिए जावा में एक पूर्ण समाधान है:

/*usage:

Util u = new Util(500); //500 items per bracket. 
String sqlBefore  = "select * from myTable where (";
List<Integer> values = new ArrayList<Integer>(Arrays.asList(1,2,4,5)); 
string sqlAfter = ") and foo = 'bar'"; 

PreparedStatement ps = u.prepareStatements(sqlBefore, values, sqlAfter, connection, "someId");
*/



import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public class Util {

    private int numValuesInClause;

    public Util(int numValuesInClause) {
        super();
        this.numValuesInClause = numValuesInClause;
    }

    public int getNumValuesInClause() {
        return numValuesInClause;
    }

    public void setNumValuesInClause(int numValuesInClause) {
        this.numValuesInClause = numValuesInClause;
    }

    /** Split a given list into a list of lists for the given size of numValuesInClause*/
    public List<List<Integer>> splitList(
            List<Integer> values) {


        List<List<Integer>> newList = new ArrayList<List<Integer>>(); 
        while (values.size() > numValuesInClause) {
            List<Integer> sublist = values.subList(0,numValuesInClause);
            List<Integer> values2 = values.subList(numValuesInClause, values.size());   
            values = values2; 

            newList.add( sublist);
        }
        newList.add(values);

        return newList;
    }

    /**
     * Generates a series of split out in clause statements. 
     * @param sqlBefore ""select * from dual where ("
     * @param values [1,2,3,4,5,6,7,8,9,10]
     * @param "sqlAfter ) and id = 5"
     * @return "select * from dual where (id in (1,2,3) or id in (4,5,6) or id in (7,8,9) or id in (10)"
     */
    public String genInClauseSql(String sqlBefore, List<Integer> values,
            String sqlAfter, String identifier) 
    {
        List<List<Integer>> newLists = splitList(values);
        String stmt = sqlBefore;

        /* now generate the in clause for each list */
        int j = 0; /* keep track of list:newLists index */
        for (List<Integer> list : newLists) {
            stmt = stmt + identifier +" in (";
            StringBuilder innerBuilder = new StringBuilder();

            for (int i = 0; i < list.size(); i++) {
                innerBuilder.append("?,");
            }



            String inClause = innerBuilder.deleteCharAt(
                    innerBuilder.length() - 1).toString();

            stmt = stmt + inClause;
            stmt = stmt + ")";


            if (++j < newLists.size()) {
                stmt = stmt + " OR ";
            }

        }

        stmt = stmt + sqlAfter;
        return stmt;
    }

    /**
     * Method to convert your SQL and a list of ID into a safe prepared
     * statements
     * 
     * @throws SQLException
     */
    public PreparedStatement prepareStatements(String sqlBefore,
            ArrayList<Integer> values, String sqlAfter, Connection c, String identifier)
            throws SQLException {

        /* First split our potentially big list into lots of lists */
        String stmt = genInClauseSql(sqlBefore, values, sqlAfter, identifier);
        PreparedStatement ps = c.prepareStatement(stmt);

        int i = 1;
        for (int val : values)
        {

            ps.setInt(i++, val);

        }
        return ps;

    }

}

2

वसंत java.util.Lists को NamedParameterJdbcTemplate से गुजरने की अनुमति देता है , जो तर्कों की संख्या के लिए उपयुक्त (?, ?,, ..., ...) की पीढ़ी को स्वचालित करता है।

Oracle के लिए, यह ब्लॉग पोस्ट oracle.sql.ARRAY (Connection.createArrayOf Oracle के साथ काम नहीं करता है) के उपयोग पर चर्चा करता है। इसके लिए आपको अपने SQL स्टेटमेंट को संशोधित करना होगा:

SELECT my_column FROM my_table where search_column IN (select COLUMN_VALUE from table(?))

ओरेकल तालिका समारोह में मूल्य प्रयोग करने योग्य की तरह एक तालिका में पारित कर दिया सरणी बदल देती INबयान।


1

इंस्ट्र फ़ंक्शन का उपयोग करने का प्रयास करें?

select my_column from my_table where  instr(?, ','||search_column||',') > 0

फिर

ps.setString(1, ",A,B,C,"); 

माना जाता है कि यह थोड़ा गंदा हैक है, लेकिन यह sql इंजेक्शन के अवसरों को कम करता है। वैसे भी ओरेकल में काम करता है।


ओह, और मुझे पता है कि यह
stjohnroe

यह कुछ तारों के लिए काम नहीं करेगा, उदाहरण के लिए, यदि स्ट्रिंग में ',' है।
डेविड पोर्टेबेला

1

Sormula एक पैरामीटर के रूप में java.util.Collection ऑब्जेक्ट की आपूर्ति करने की अनुमति देकर SQL IN ऑपरेटर का समर्थन करता है। यह एक के साथ एक तैयार बयान बनाता है? तत्वों में से प्रत्येक संग्रह के लिए। उदाहरण 4 देखें ( उदाहरण के लिए SQL एक टिप्पणी है जो यह स्पष्ट करने के लिए है कि क्या बनाया गया है लेकिन Sormula द्वारा उपयोग नहीं किया गया है)।


1

के बजाय का उपयोग करने का

SELECT my_column FROM my_table where search_column IN (?)

Sql स्टेटमेंट का उपयोग करें

select id, name from users where id in (?, ?, ?)

तथा

preparedStatement.setString( 1, 'A');
preparedStatement.setString( 2,'B');
preparedStatement.setString( 3, 'C');

या संग्रहीत कार्यविधि का उपयोग करें यह सबसे अच्छा समाधान होगा, क्योंकि sql स्टेटमेंट्स को डाटाबेस सर्वर में संकलित और संग्रहीत किया जाएगा


1

मैं तैयार बयान से संबंधित कई सीमाएँ पार कर गया:

  1. तैयार किए गए बयानों को केवल एक ही सत्र (पोस्टग्रेज) के अंदर कैश किया जाता है, इसलिए यह वास्तव में कनेक्शन पूलिंग के साथ ही काम करेगा
  2. @BalusC द्वारा प्रस्तावित कई अलग-अलग तैयार किए गए बयानों के कारण कैश ओवरफिल हो सकता है और पहले कैश्ड स्टेटमेंट को हटा दिया जाएगा
  3. क्वेरी को अनुकूलित करना होगा और सूचकांकों का उपयोग करना होगा। स्पष्ट लगता है, हालांकि किसी भी (ARRAY ...) उदाहरण @Boris द्वारा प्रस्तावित शीर्ष उत्तरों में से एक में सूचकांकों का उपयोग नहीं किया जा सकता है और कैशिंग के बावजूद क्वेरी धीमी होगी
  4. तैयार किया गया स्टेटमेंट क्वेरी प्लान को भी बताता है और स्टेटमेंट में निर्दिष्ट किसी भी पैरामीटर के वास्तविक मान अनुपलब्ध हैं।

प्रस्तावित समाधानों के बीच, मैं वह चुनूंगा जो क्वेरी के प्रदर्शन को कम नहीं करता है और प्रश्नों की कम संख्या बनाता है। यह @ 4 लिंक से # 4 (कुछ प्रश्नों को बैचते हुए) होगा या अनावश्यक 'के लिए पूर्ण मान निर्दिष्ट करेगा?' @Vladimir Dyuzhev द्वारा प्रस्तावित निशान


1

मैंने अभी इसके लिए एक PostgreSQL-विशिष्ट विकल्प पर काम किया है। यह एक हैक का एक सा है, और अपने स्वयं के पेशेवरों और विपक्ष और सीमाओं के साथ आता है, लेकिन यह काम करने लगता है और एक विशिष्ट विकास भाषा, प्लेटफॉर्म या पीजी चालक तक सीमित नहीं है।

पाठ्यक्रम की चाल एक एकल पैरामीटर के रूप में मानों की मनमानी लंबाई संग्रह को पारित करने का एक तरीका खोजने के लिए है, और डीबी को कई मूल्यों के साथ इसे पहचानना है। मेरे पास जो समाधान काम कर रहा है, वह संग्रह में मूल्यों से एक सीमांकित स्ट्रिंग का निर्माण करना है, उस स्ट्रिंग को एक पैरामीटर के रूप में पास करें, और स्ट्रिंग_टो_अरे () का उपयोग पोस्टग्रेक्यूएल के लिए आवश्यक कास्टिंग के साथ ठीक से उपयोग करने के लिए करें।

इसलिए यदि आप "फू", "ब्ला", और "एबीसी" को खोजना चाहते हैं, तो आप उन्हें एक साथ एक स्ट्रिंग में समेट सकते हैं: 'फू, ब्ला, एबीसी'। यहाँ सीधे एसक्यूएल है:

select column from table
where search_column = any (string_to_array('foo,blah,abc', ',')::text[]);

आप स्पष्ट रूप से स्पष्ट कास्ट को बदल देंगे जो आप चाहते थे कि आपका परिणामी मूल्य सरणी होना चाहिए - int, text, uuid, आदि और क्योंकि फ़ंक्शन एकल स्ट्रिंग मान ले रहा है (या दो मुझे लगता है, यदि आप सीमांकक को अनुकूलित करना चाहते हैं साथ ही), आप इसे तैयार विवरण में एक पैरामीटर के रूप में पारित कर सकते हैं:

select column from table
where search_column = any (string_to_array($1, ',')::text[]);

यह तुलनात्मक चीज़ों का समर्थन करने के लिए पर्याप्त लचीला है:

select column from table
where search_column like any (string_to_array('foo%,blah%,abc%', ',')::text[]);

फिर से, कोई सवाल नहीं यह एक हैक है, लेकिन यह काम करता है और आपको अभी भी पूर्व-संकलित तैयार कथनों का उपयोग करने की अनुमति देता है जो सुरक्षा और साथ (शायद) प्रदर्शन लाभ के साथ * अहम * असतत पैरामीटर लेते हैं। क्या यह उचित है और वास्तव में प्रदर्शनकारी है? स्वाभाविक रूप से, यह निर्भर करता है, जैसा कि आपने स्ट्रिंग पार्सिंग प्राप्त की है और संभवतः आपकी क्वेरी से पहले भी चल रहा है। यदि आप तीन, पांच, कुछ दर्जन मान भेजने की उम्मीद कर रहे हैं, तो निश्चित रूप से, यह शायद ठीक है। कुछ हजार? हाँ, शायद इतना नहीं। YMMV, सीमाएं और बहिष्करण लागू होते हैं, कोई वारंटी एक्सप्रेस या निहित नहीं है।

लेकिन यह काम करता है।


0

बस पूर्णता के लिए: जब तक मूल्यों का सेट बहुत बड़ा नहीं होता है, तब तक आप केवल एक कथन जैसे स्ट्रिंग-निर्माण कर सकते हैं

... WHERE tab.col = ? OR tab.col = ? OR tab.col = ?

जो तब आप तैयार करने के लिए पारित कर सकते हैं (), और फिर सभी मूल्यों को सेट करने के लिए लूप में setXXX () का उपयोग करें। यह यकीनी लग रहा है, लेकिन कई "बड़े" वाणिज्यिक सिस्टम नियमित रूप से इस तरह का काम करते हैं जब तक कि वे डीबी-विशिष्ट सीमाओं को नहीं मारते हैं, जैसे कि ओरेकल में बयानों के लिए 32 केबी (मुझे लगता है कि यह) है।

बेशक आपको यह सुनिश्चित करने की ज़रूरत है कि सेट कभी भी अनुचित रूप से बड़ा नहीं होगा, या उस घटना में फंसने में त्रुटि न करें।


हाँ तुम सही हो। इस मामले में मेरा लक्ष्य हर बार अलग-अलग संख्याओं के साथ रेडीस्टेडमेंट का पुन: उपयोग करना था।
क्रिस माज़ोला

3
"OR" के प्रयोग से इरादे में बाधा आएगी। स्टिक "IN" के रूप में पढ़ने के लिए आसान है और इरादा अधिक स्पष्ट है। स्विच करने का एकमात्र कारण यह है कि यदि क्वेरी प्लान अलग थे।
जेम्स स्कैच

0

एडम के विचार के बाद। अपने तैयार किए गए कथन को my_table से my_table सेलेक्ट करें जहाँ search_column (#) एक स्ट्रिंग x बनाएँ और इसे "?;?" आपके मूल्यों की सूची के आधार पर फिर अपने नए स्ट्रिंग एक्स के लिए क्वेरी में # बदलें


0

अपनी सूची में आइटम्स की संख्या से मेल खाने वाले नंबर को तैयार करने के लिए क्वेरी स्ट्रिंग बनाएं। यहाँ एक उदाहरण है:

public void myQuery(List<String> items, int other) {
  ...
  String q4in = generateQsForIn(items.size());
  String sql = "select * from stuff where foo in ( " + q4in + " ) and bar = ?";
  PreparedStatement ps = connection.prepareStatement(sql);
  int i = 1;
  for (String item : items) {
    ps.setString(i++, item);
  }
  ps.setInt(i++, other);
  ResultSet rs = ps.executeQuery();
  ...
}

private String generateQsForIn(int numQs) {
    String items = "";
    for (int i = 0; i < numQs; i++) {
        if (i != 0) items += ", ";
        items += "?";
    }
    return items;
}

5
अब StringBuilder का उपयोग करने की कोई आवश्यकता नहीं है। कंपाइलर वैसे भी StringBuilder.append () को + संकेत देता है, इसलिए कोई प्रदर्शन हिट नहीं है। अपने आप को आजमाएं :)
neu242

5
@ neu242: अरे हां, कंपाइलर उपयोग करता है StringBuilder। लेकिन उस तरीके से नहीं जैसा आप सोचते हैं। विघटित generateQsForInआप देख सकते हैं कि प्रति लूप पुनरावृत्ति में दो नए StringBuilderआवंटित किए जाते हैं और toStringप्रत्येक पर कॉल किया जाता है। StringBuilderअनुकूलन केवल की तरह सामान पकड़ता "x" + i+ "y" + jलेकिन एक अभिव्यक्ति से बाहर भी नहीं करता है।
एएच

@ neu242 क्या आप ps.setObject(1,items)सूची पर पुनरावृति और फिर सेटिंग करने के बजाय उपयोग नहीं कर सकते paramteres?
नेहा चौधरी

0

अलग-अलग वैकल्पिक दृष्टिकोण हैं जो कि हम तैयार किए गए इनस्टॉजमेंट में IN क्लॉज के लिए उपयोग कर सकते हैं।

  1. एकल क्वेरी का उपयोग करना - सबसे धीमा प्रदर्शन और संसाधन गहन
  2. StoredProcedure का उपयोग करना - सबसे तेज़ लेकिन डेटाबेस विशिष्ट
  3. तैयारी के लिए डायनामिक क्वेरी बनाना - अच्छा प्रदर्शन लेकिन कैशिंग का लाभ नहीं मिलता है और हर बार रेडीस्टेडमेंट का पुन: उपयोग किया जाता है।
  4. तैयार किए गए प्रश्नों में NULL का उपयोग करें - जब आप क्लॉज आर्ग्युमेंट्स की सीमा को जानते हैं तो ऑप्टिमल परफॉर्मेंस बढ़िया काम करता है। यदि कोई सीमा नहीं है, तो आप बैच में प्रश्नों का निष्पादन कर सकते हैं। नमूना कोड स्निपेट है;

        int i = 1;
        for(; i <=ids.length; i++){
            ps.setInt(i, ids[i-1]);
        }
    
        //set null for remaining ones
        for(; i<=PARAM_SIZE;i++){
            ps.setNull(i, java.sql.Types.INTEGER);
        }

आप इन वैकल्पिक तरीकों के बारे में अधिक जानकारी यहां देख सकते हैं


"तैयारी के लिए गतिशील क्वेरी बनाना - अच्छा प्रदर्शन लेकिन कैशिंग का लाभ नहीं मिलता है और हर बार तैयार किया जाता है।" कैशिंग और recompiles से बचने के लिए एक तैयार बयान अच्छा प्रदर्शन करता है। इसलिए, मैं आपके दावे से सहमत नहीं हूं। हालाँकि, जब आप कॉमा को कॉन्टेक्ट / डायनामिक इनपुट सीमित कर रहे हैं, तो यह SQL इंजेक्शन को रोक देगा।
ब्रेंडन

मैं आपके साथ सहमत हूं, हालांकि यहां "अच्छा प्रदर्शन" इस विशिष्ट परिदृश्य के लिए है। यह दृष्टिकोण 1 से बेहतर प्रदर्शन कर रहा है, हालांकि दृष्टिकोण 2 सबसे तेज़ है।
पंकज

0

कुछ स्थितियों के लिए regexp मदद कर सकता है। यहाँ एक उदाहरण मैंने ओरेकल पर जाँचा है, और यह काम करता है।

select * from my_table where REGEXP_LIKE (search_column, 'value1|value2')

लेकिन इसके साथ कई कमियां भी हैं:

  1. जो भी कॉलम लागू किया गया है, उसे कम से कम निहित रूप से, varchar / char में बदलना चाहिए।
  2. विशेष पात्रों के साथ सावधान रहने की आवश्यकता है।
  3. यह प्रदर्शन को धीमा कर सकता है - मेरे मामले में संस्करण में सूचकांक और रेंज स्कैन का उपयोग करता है, और REGEXP संस्करण पूर्ण स्कैन करते हैं।

0

विभिन्न मंचों में विभिन्न समाधानों की जांच करने और एक अच्छा समाधान नहीं ढूंढने के बाद, मुझे लगता है कि मैं जिस हैक के साथ आया था, वह कोड का पालन करने के लिए सबसे आसान है:

उदाहरण: मान लीजिए कि 'IN' क्लॉज में पास होने के लिए आपके पास कई पैरामीटर हैं। बस 'IN' क्लॉज़ के अंदर एक डमी स्ट्रिंग डालें, "PARAM" उन मापदंडों की सूची को निरूपित करें जो इस डमी स्ट्रिंग के स्थान पर आ रहे हैं।

    select * from TABLE_A where ATTR IN (PARAM);

आप अपने जावा कोड में सभी मापदंडों को एक एकल स्ट्रिंग चर में एकत्र कर सकते हैं। इसे इस प्रकार किया जा सकता है:

    String param1 = "X";
    String param2 = "Y";
    String param1 = param1.append(",").append(param2);

आप हमारे मामले में, एक एकल स्ट्रिंग चर, 'परम 1' में अल्पविराम द्वारा अलग किए गए अपने सभी मापदंडों को जोड़ सकते हैं।

सभी मानकों को एक एकल स्ट्रिंग में एकत्रित करने के बाद, आप केवल इस क्वेरी में, यानी, पैरामीटर 1 के साथ, इस मामले में "PARAM" में डमी टेक्स्ट को बदल सकते हैं। यहाँ है आपको क्या करने की जरूरत है:

    String query = query.replaceFirst("PARAM",param1); where we have the value of query as 

    query = "select * from TABLE_A where ATTR IN (PARAM)";

अब आप अपने क्वेरी को निष्पादित (निष्पादित) विधि का उपयोग करके निष्पादित कर सकते हैं। बस सुनिश्चित करें कि आपके क्वेरी में कहीं भी "PARAM" शब्द नहीं है। आप यह सुनिश्चित करने के लिए कि "PARAM" शब्द के बजाय विशेष वर्ण और अक्षर के संयोजन का उपयोग कर सकते हैं ताकि यह सुनिश्चित हो सके कि इस तरह के शब्द के क्वेरी में आने की कोई संभावना नहीं है। आशा है आपको समाधान मिल गया होगा

नोट: हालांकि यह एक तैयार क्वेरी नहीं है, यह वह काम करता है जो मैं चाहता था कि मेरा कोड ऐसा हो।


0

सिर्फ पूर्णता के लिए और क्योंकि मैंने किसी और को यह सुझाव देते नहीं देखा:

ऊपर दिए गए किसी भी जटिल सुझाव को लागू करने से पहले विचार करें कि क्या एसक्यूएल इंजेक्शन वास्तव में आपके परिदृश्य की समस्या है।

कई मामलों में IN (...) को प्रदान की गई मान आईडी की एक सूची है जो इस तरह से बनाई गई है कि आप सुनिश्चित कर सकते हैं कि कोई इंजेक्शन संभव नहीं है ... (उदाहरण के लिए पिछले के परिणाम some_id से some_table जहां some_condition।)

यदि ऐसा है तो आप इस मूल्य को संक्षिप्त कर सकते हैं और सेवाओं या इसके लिए तैयार विवरण का उपयोग नहीं कर सकते हैं या इस क्वेरी के अन्य मापदंडों के लिए उनका उपयोग कर सकते हैं।

query="select f1,f2 from t1 where f3=? and f2 in (" + sListOfIds + ");";

0

SQLed खंड से निपटने के लिए कोई भी अच्छा तरीका तैयार करता है। प्रति http://www.javaranch.com/journal/200510/Journal200510.jsp#a2 "आप उन चीजों को स्थानापन्न नहीं कर सकते हैं जो SQL कथन का हिस्सा बनने के लिए हैं। यह आवश्यक है क्योंकि यदि SQL स्वयं बदल सकता है, तो ड्राइवर बयान को रोक नहीं सकता है। इसमें SQL इंजेक्शन के हमलों को रोकने का अच्छा दुष्प्रभाव भी है। " मैंने निम्नलिखित दृष्टिकोण का उपयोग करके समाप्त किया:

String query = "SELECT my_column FROM my_table where search_column IN ($searchColumns)";
query = query.replace("$searchColumns", "'A', 'B', 'C'");
Statement stmt = connection.createStatement();
boolean hasResults = stmt.execute(query);
do {
    if (hasResults)
        return stmt.getResultSet();

    hasResults = stmt.getMoreResults();

} while (hasResults || stmt.getUpdateCount() != -1);

0

SetArray सबसे अच्छा समाधान है लेकिन इसके कई पुराने ड्राइवरों के लिए उपलब्ध नहीं है। Java8 में निम्न वर्कअराउंड का उपयोग किया जा सकता है

String baseQuery ="SELECT my_column FROM my_table where search_column IN (%s)"

String markersString = inputArray.stream().map(e -> "?").collect(joining(","));
String sqlQuery = String.format(baseSQL, markersString);

//Now create Prepared Statement and use loop to Set entries
int index=1;

for (String input : inputArray) {
     preparedStatement.setString(index++, input);
}

यह समाधान अन्य बदसूरत से बेहतर है जबकि लूप समाधान जहां क्वेरी स्ट्रिंग मैनुअल पुनरावृत्तियों द्वारा बनाई गई है


0

यह मेरे लिए काम किया (psuedocode):

public class SqlHelper
{
    public static final ArrayList<String>platformList = new ArrayList<>(Arrays.asList("iOS","Android","Windows","Mac"));

    public static final String testQuery = "select * from devices where platform_nm in (:PLATFORM_NAME)";
}

बाध्यकारी को निर्दिष्ट करें:

public class Test extends NamedParameterJdbcDaoSupport
public List<SampleModelClass> runQuery()
{
    //define rowMapper to insert in object of SampleClass
    final Map<String,Object> map = new HashMap<>();
    map.put("PLATFORM_LIST",DeviceDataSyncQueryConstants.platformList);
    return getNamedParameterJdbcTemplate().query(SqlHelper.testQuery, map, rowMapper)
}

0

SQLite और Oracle डेटाबेस के लिए मेरा उदाहरण।

पहली बार लूप एक रेडीस्टेमेंट ऑब्जेक्ट बनाने के लिए है।

दूसरा फॉर लूप रेडीस्टेटमेंट पैरामीटर्स के लिए सप्लीमेंट वैल्यूज़ के लिए है।

List<String> roles = Arrays.asList("role1","role2","role3");
Map<String, String> menu = getMenu(conn, roles);

public static Map<String, String> getMenu(Connection conn, List<String> roles ) {
    Map<String, String> menu = new LinkedHashMap<String, String>();

    PreparedStatement stmt;
    ResultSet rset;
    String sql;
    try {
        if (roles == null) {
            throw new Exception();
        }
        int size = roles.size();
        if (size == 0) {
            throw new Exception("empty list");
        }
        StringBuilder sb = new StringBuilder();
        sb.append("select page_controller, page_name from pages "
                + " where page_controller in (");
        for (int i = 0; i < size; i++) {
            sb.append("?,");
        }
        sb.setLength(sb.length() - 1);
        sb.append(") order by page_id");
        sql = sb.toString();
        stmt = conn.prepareStatement(sql);
        for (int i = 0; i < size; i++) {
            stmt.setString(i + 1, roles.get(i));
        }
        rset = stmt.executeQuery();
        while (rset.next()) {
            menu.put(rset.getString(1), rset.getString(2));
        }

        conn.close();
    } catch (Exception ex) {
        logger.info(ex.toString());
        try {
            conn.close();
        } catch (SQLException e) {
        }
        return menu;
    }
    return menu;
}

-3

मेरा समाधान (जावास्क्रिप्ट)

    var s1 = " SELECT "

 + "FROM   table t "

 + "  where t.field in ";

  var s3 = '(';

  for(var i =0;i<searchTerms.length;i++)
  {
    if(i+1 == searchTerms.length)
    {
     s3  = s3+'?)';
    }
    else
    {
        s3  = s3+'?, ' ;
    }
   }
    var query = s1+s3;

    var pstmt = connection.prepareStatement(query);

     for(var i =0;i<searchTerms.length;i++)
    {
        pstmt.setString(i+1, searchTerms[i]);
    }

SearchTerms वह सरणी है जिसमें आपका इनपुट / कुंजियाँ / फ़ील्ड आदि शामिल हैं

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.