मैं अपने Android एप्लिकेशन में दो SQLite टेबल कैसे शामिल करूं?


95

पृष्ठभूमि

मेरे पास एक एंड्रॉइड प्रोजेक्ट है जिसमें दो टेबल के साथ एक डेटाबेस है: tbl_questionऔर tbl_alternative

सवालों और विकल्पों के साथ विचारों को आबाद करने के लिए मैं श्रापियों का उपयोग कर रहा हूं। जब तक मुझे दो तालिकाओं में शामिल होने की कोशिश नहीं होती, तब तक मुझे जो डेटा चाहिए, उसे प्राप्त करने में कोई समस्या नहीं है।

    Tbl_question  
    -------------
    _ id  
    सवाल  
    श्रेणी ID  
    Tbl_alternative
    ---------------
    _ id 
    questionid 
    श्रेणी ID 
    विकल्प

मुझे निम्नलिखित जैसा कुछ चाहिए:

SELECT tbl_question.question, tbl_alternative.alternative where 
categoryid=tbl_alternative.categoryid AND tbl_question._id = 
tbl_alternative.questionid.` 

यह मेरा प्रयास है:

public Cursor getAlternative(long categoryid) {
            String[] columns = new String[] { KEY_Q_ID, KEY_IMAGE, KEY_QUESTION, KEY_ALT, KEY_QID};
             String whereClause = KEY_CATEGORYID + "=" + categoryid +" AND "+ KEY_Q_ID +"="+ KEY_QID;
             Cursor cursor = mDb.query(true, DBTABLE_QUESTION + " INNER JOIN "+ DBTABLE_ALTERNATIVE, columns, whereClause, null, null, null, null, null);
             if (cursor != null) {
                  cursor.moveToFirst();
             }
             return cursor;

मैं नियमित एसक्यूएल की तुलना में कठिन प्रश्नों को बनाने के लिए यह तरीका ढूंढता हूं, लेकिन इस तरह का उपयोग करने की सलाह दी है क्योंकि यह कम त्रुटि वाला है।

सवाल

मैं अपने आवेदन में दो SQLite टेबल कैसे शामिल करूं?


आप क्या त्रुटि प्राप्त कर रहे हैं? आप एक स्ट्रिंग शाब्दिक के साथ सचित्र स्ट्रिंग की जगह द्वारा परीक्षण की कोशिश की? (एफडब्ल्यूआईडब्ल्यू, मुझे 1986 या उसके बाद से एक कर्सर का उपयोग नहीं करना पड़ा। लेकिन मैं एंड्रॉइड के लिए विकसित नहीं हुआ।)
माइक शेरिल 'कैट रिकॉल'

मैं यह नहीं देखता कि कर्सर कोड ब्लॉक में इनर-जॉइन-कॉलम कहाँ और कैसे निर्दिष्ट किए जा रहे हैं। एसक्यूएल होगा "टी 1 भीतरी से वांछित-कॉलम-सूची का चयन T1.questionid = T2.questionid और T1.categoryid = T2.categoryid जहां T1.categoryid = {वांछित श्रेणी मूल्य} को टी 2 में शामिल होने के"
टिम

यह मेरी त्रुटि है: अस्पष्ट कॉलम नाम: _id:, संकलन करते समय: चयन करें DISTINCT _id, छवि, प्रश्न, विकल्प, प्रश्नावली से tbl_question INNER JOIN tbl_alternative WHO श्रेणीवादि = 2 और _id = questionid। इसलिए मुझे लगता है कि मुझे tbl_question._id = tbl_alternative.questionid निर्दिष्ट करने की आवश्यकता है, लेकिन मुझे नहीं पता कि यह कैसे करना है जिस तरह से मैं ऊपर उपयोग करता हूं। ; Tbl_question अंदरूनी से "चुनें 'शामिल हों tbl_alternative पर tbl_question._id = tbl_alternative.questionid और tbl_question.categoryid = tbl_alternative.categoryid = CategoryID: और मैं क्या अगर मैं एक" नियमित "एसक्यूएल-वाक्य विन्यास का उपयोग वापस जाने के लिए पता नहीं है
kakka47

@ समय: जिस तरह से आप इसे करते हैं, मैं डीबी-हेल्पर वर्ग में विधि कैसे बनाऊं? क्या मुझे एक कर्सर नहीं लौटाना चाहिए? मैं जाते हुए सीख रहा हूं, कोई भी सुझाव जो मेरे कोड को बेहतर बनाता है मैं इसके लिए आभारी हूं!
kakka47

यहाँ मैंने उत्तर stackoverflow.com/questions/31567564/…
सागर

जवाबों:


204

आपको रॉविडे विधि की आवश्यकता है

उदाहरण:

private final String MY_QUERY = "SELECT * FROM table_a a INNER JOIN table_b b ON a.id=b.other_id WHERE b.property_id=?";

db.rawQuery(MY_QUERY, new String[]{String.valueOf(propertyId)});

उपयोग ? कच्चे sql क्वेरी में मान डालने के बजाय बाइंडिंग।


1
@necromancer VIEWसे बेहतर विकल्प कैसे बनाते हैं rawQuery?
मुहम्मद बाबर

क्वेरी के बाद क्या किया जाना चाहिए? आपको कैसे पता चलेगा कि कौन सी आईडी किस तालिका से संबंधित है, और क्या होगा यदि दोनों तालिकाओं में किसी स्तंभ के लिए समान स्तंभ नाम हो? या अगर दूसरी तालिका के लिए कई आइटम हैं?
एंड्रॉयड डेवलपर

@ एंड्रॉइड-डेवलपर "क्वेरी के बाद क्या किया जाना चाहिए?" - आपको एक कर्सर मिलता है, जो आप डेटा के साथ चाहते हैं: पी; 2. "आप किस आईडी को जानते हैं ..." - यह एक JOIN है, इसलिए किस प्रकार पर निर्भर करता है , आपको ALWAYS, NEVER, या MAYBE पॉप्युलेटेड कुंजियाँ मिल सकती हैं; 3. "... कुछ कॉलम के लिए एक ही कॉलम नाम" - हो सकता है, लेकिन अस्पष्टता को हटाया जा सकता है। ईमानदारी से मुझे नहीं पता कि क्या आप getColumnIndex का उपयोग करके "Table.column" के साथ ला सकते हैं, आप हमेशा इंडेक्स की गणना मैन्युअल रूप से कर सकते हैं, बस इसे डिबग-टेस्ट कर सकते हैं; 4. "दूसरी तालिका के लिए कई आइटम" भी सम्मिलित प्रकार पर निर्भर करता है।
leRobot

यह मान लेना कि एक 1 से कई संबंधों (जैसे RawContactsEntity ) का एक पूर्ण ईमेल शामिल है , आप "कई" टेबल पर अशक्त कुंजी के साथ पंक्तियाँ प्राप्त कर सकते हैं, लेकिन कभी भी "1" तालिका पर अपने कर्सर को शाखा न दें जैसे: जबकि (कर्सर.moveToNext () {if (कर्सर.getValue (getManyTableKeyIndex ()) == NULL) {/ * यह एक नो-रिलेशन की पंक्ति है, केवल इसमें 1 # टेबल डेटा /} बाकी है {/ यह है एक रिश्ता है, तो वहाँ दोनों तालिकाओं से डेटा है * /}} कर्सर.close ();
leRobot

मैं "नहीं माता-पिता कई" पंक्तियों के लिए एक और शाखा जोड़ना भूल गया, जिसे आप अभी भी फुल ओवर जॉइन के साथ प्राप्त कर सकते हैं, लेकिन आमतौर पर यदि संबंध सख्त नहीं है (मुझे यकीन नहीं है कि एंड्रॉइड रिश्तों को लागू करता है)। वास्तव में अस्पष्ट कॉलम प्राप्त करना नहीं जानते, लेकिन आप किसी भी SQLite CLI पर कॉलम अस्पष्टता के साथ एक दृश्य घोषित करके इसका परीक्षण कर सकते हैं और देख सकते हैं कि उन कॉलमों को "SELECT * FROM view_x" क्वेरी पर क्या नाम मिलता है। तो आप बस लागू करें कि जो भी Android सहायक स्वाद चाहते हैं (.query () / .rawQuery () ...)
leRobot

20

एक वैकल्पिक तरीका यह है कि एक दृश्य का निर्माण किया जाए जो बाद में एक तालिका की तरह क्वियर किया जाता है। कई डेटाबेस प्रबंधकों में एक दृश्य का उपयोग करने से बेहतर प्रदर्शन हो सकता है।

CREATE VIEW xyz SELECT q.question, a.alternative  
   FROM tbl_question AS q, tbl_alternative AS a
  WHERE q.categoryid = a.categoryid 
    AND q._id = a.questionid;

यह स्मृति से है, इसलिए कुछ वाक्यात्मक मुद्दे हो सकते हैं। http://www.sqlite.org/lang_createview.html

मैं इस दृष्टिकोण का उल्लेख करता हूं क्योंकि तब आप SQLiteQueryBuilder का उपयोग उस दृश्य के साथ कर सकते हैं जैसा कि आपने अनुमान लगाया था कि इसे पसंद किया गया था।


4
जब यह आरडीबीएमएस जैसे ओरेकल की बात आती है, तो विचार आपको कुछ प्रदर्शन लाभ दे सकते हैं लेकिन मेरे अनुभव में, उनका उपयोग केवल प्रदर्शन या रिपोर्टिंग उद्देश्यों के लिए आवश्यक है। या इसे दूसरे तरीके से रखने के लिए, आप अपने द्वारा उपयोग की जाने वाली प्रत्येक जुड़ने वाली क्वेरी के लिए एक दृश्य नहीं बनाते हैं। और विशेष रूप से SQLite में, मुझे विश्वास नहीं है कि कोई भी प्रदर्शन लाभ है - इस प्रश्न के उत्तर के अनुसार, SQLite एक उप-वर्ग का उपयोग करके क्वेरी को फिर से लिखता है। stackoverflow.com/questions/25577407/performance-penalty-for-unused-view#25580319 Android का API ओपी क्या कर रहा है इसके लिए सीमित हो सकता है लेकिन rawQuery()सही उत्तर है।
स्पाकार्की 21

13

@ Pawelzieba के उत्तर के अलावा, जो निश्चित रूप से सही है, दो तालिकाओं में शामिल होने के लिए, जबकि आप INNER JOINइस तरह का उपयोग कर सकते हैं

SELECT * FROM expense INNER JOIN refuel
ON exp_id = expense_id
WHERE refuel_id = 1

कच्चे क्वेरी के माध्यम से इस तरह -

String rawQuery = "SELECT * FROM " + RefuelTable.TABLE_NAME + " INNER JOIN " + ExpenseTable.TABLE_NAME
        + " ON " + RefuelTable.EXP_ID + " = " + ExpenseTable.ID
        + " WHERE " + RefuelTable.ID + " = " +  id;
Cursor c = db.rawQuery(
        rawQuery,
        null
);

क्वेरी के आदिम तरीके से SQLite के पिछड़े संगत समर्थन के कारण, हम उस कमांड को इस में बदल देते हैं -

SELECT *
FROM expense, refuel
WHERE exp_id = expense_id AND refuel_id = 1

और इसलिए SQLiteDatabase.query () सहायक विधि का एडवांटेज लेने में सक्षम हो

Cursor c = db.query(
        RefuelTable.TABLE_NAME + " , " + ExpenseTable.TABLE_NAME,
        Utils.concat(RefuelTable.PROJECTION, ExpenseTable.PROJECTION),
        RefuelTable.EXP_ID + " = " + ExpenseTable.ID + " AND " + RefuelTable.ID + " = " +  id,
        null,
        null,
        null,
        null
);

विस्तृत ब्लॉग पोस्ट के लिए इस http://blog.championswimmer.in/2015/12/doing-a-table-join-in-android-without-use-rawquery को देखें


1
मुझे समझ नहीं आ रहा है कि Utils.concat कहाँ से आता है।
nicoqueijo

1
यह एक अच्छा तरीका है, लेकिन काम नहीं करेगा यदि किसी तालिका में किसी स्तंभ का नाम किसी अन्य तालिका के स्तंभ नाम के समान है। जैसे यदि दोनों तालिकाओं में नाम आईडी वाला एक कॉलम है, तो यह फेंक देगाandroid.database.sqlite.SQLiteException: ambiguous column name
अनूप शर्मा

8

"अस्पष्ट कॉलम" का आमतौर पर मतलब है कि कम से कम दो तालिकाओं में समान स्तंभ नाम दिखाई देता है; डेटाबेस इंजन यह नहीं बता सकता है कि आपको कौन सा चाहिए। अस्पष्टता को दूर करने के लिए पूर्ण तालिका नामों या टेबल उपनामों का उपयोग करें।

यहाँ एक उदाहरण है जो मैंने अपने संपादक में किया है। यह किसी और की समस्या से है, लेकिन वैसे भी समझदारी चाहिए।

select P.* 
from product_has_image P
inner join highest_priority_images H 
        on (H.id_product = P.id_product and H.priority = p.priority)

हां, मुझे उस पर शक था। लेकिन मुझे नहीं पता था कि टेबल को कैसे निर्दिष्ट किया जाए, क्योंकि रास्ते: DBTABLE_QUESTION.KEY_QUESTION, काम नहीं किया। लेकिन जब मैं रॉ-वाई का उपयोग करता हूं, तो यह परिभाषित करना आसान था कि कौन सी तालिका किस कॉलम से संबंधित है।
काका
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.