Как мне объединить две таблицы SQLite в моем приложении для Android?

80

Фон

У меня есть проект Android, у которого есть база данных с двумя таблицами: tbl_question и tbl_alternative.

Чтобы заполнить представления вопросами и альтернативами, я использую курсоры. Нет никаких проблем с получением данных, которые мне нужны, пока я не попытаюсь присоединиться к двум таблицам.

    Tbl_question  
    -------------
    _id  
    question  
    categoryid  
    Tbl_alternative
    ---------------
    _id 
    questionid 
    categoryid 
    alternative

Мне нужно что-то вроде следующего:

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;

Я нахожу этот способ, чтобы сформировать запросы сложнее обычного SQL, но получил совет использовать этот способ, поскольку он менее подвержен ошибкам.

Вопрос

Как мне присоединиться к двум таблицам SQLite в моем приложении?

  • 0
    Какую ошибку вы получаете? Вы пробовали проверить, заменив объединенную строку строковым литералом? (FWIW, мне не приходилось использовать курсор с 1986 года или около того. Но я не разрабатываю для Android.)
  • 0
    Я не вижу, где / как внутренние столбцы соединения указываются в блоке кода курсора. SQL будет "выбрать список желаемых столбцов из внутреннего соединения T1 T2 на T1.questionid = T2.questionid и T1.categoryid = T2.categoryid где T1.categoryid = {желаемое значение категории}"
Показать ещё 3 комментария
Теги:

4 ответа

183
Лучший ответ

Вам нужен rawQuery.

Пример:

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-запросу.

  • 0
    достойный ответ, но -1 относительно лучшего варианта, предложенного @phreed
  • 24
    @ necromancer, этот ответ не заслуживает отрицательного ответа. Просто прочитайте о том, что означает понижение в стековом потоке : Use your downvotes whenever you encounter an egregiously sloppy, no-effort-expended post, or an answer that is clearly and perhaps dangerously incorrect. ,
Показать ещё 9 комментариев
19

Альтернативный способ - создать представление, которое затем запрашивается точно так же, как таблица. Во многих менеджерах баз данных использование представления может привести к повышению производительности.

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 с представлением, поскольку вы подразумевали, что это было предпочтительным.

  • 3
    Когда речь идет о таких же СУБД, как Oracle, представления могут дать вам некоторый прирост производительности, но, по моему опыту, они используются только тогда, когда это необходимо для целей производительности или отчетности. Или, другими словами, вы не создаете представление для каждого используемого вами запроса на присоединение. В частности, в SQLite я не верю, что какой-либо выигрыш в производительности - согласно ответу на этот вопрос, SQLite переписывает запрос, используя подзапрос. stackoverflow.com/questions/25577407/performance-penalty-for-unused-view#25580319 Android API может ограничивать то, что делает OP, но rawQuery() является правильным ответом.
7

В дополнение к ответу @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-using-rawquery

  • 0
    Я не понимаю, откуда взялся Utils.concat.
6

"Неоднозначный столбец" обычно означает, что одно и то же имя столбца отображается как минимум в двух таблицах; механизм базы данных не может определить, какой из них вы хотите. Используйте полные имена таблиц или псевдонимы таблиц, чтобы устранить двусмысленность.

Вот пример, который у меня был в моем редакторе. Это от чужой проблемы, но должно иметь смысл в любом случае.

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)
  • 0
    Да, я подозревал это. Но я не знал, как указывать таблицы, поскольку способ DBTABLE_QUESTION.KEY_QUESTION не работал. Но когда я использовал способ rawQuery, было легко определить, к какой таблице принадлежит какой столбец.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню