Подтвердить что ты не робот

Android SQLite с использованием db.query() для JOIN вместо rawquery()

У меня есть tableA, tableB и tableC таблица A и tableB соединяются таблицей A.Id(PK) = tableB.tableAId(FK) таблица B и таблица C соединяются таблицейB.Id(PK) = tableC.tableBId(FK)

Я хочу иметь возможность сделать это:

SELECT c.ALL from tableC c
INNER JOIN tableB b on c.tableBId = b.Id
INNER JOIN tableA a on b.tableAId = a.Id
WHERE a.Id = 108

Я нашел много сообщений в Интернете, которые используют db.rawquery() для реализации этого запроса. Однако я также слышал, что rawquery() менее безопасен, чем query(). Поэтому, ради поиска лучшей практики в качестве новичка, мой вопрос:

Есть ли способ реализовать этот запрос, используя db.query() вместо db.rawquery()?

заблаговременно.

4b9b3361

Ответ 1

Есть ли способ реализовать этот запрос, используя db.query() вместо db.rawquery()?

Итак, стоит сказать, что rawQuery() делает трюк. Но также существует другой подход.

query() метод предназначен для выполнения запросов по одной таблице. Но лучший способ, как JOIN таблицы в SQLite использовать SQLiteQueryBuilder и с помощью метода setTables() вы можете присоединиться.

Поэтому я рекомендую вам использовать упомянутый SQLiteQueryBuilder. Но это немного сложнее против метода rawQuery(), где вам нужно назначить только исходный оператор.

Если вы не знаете, как начать, проверьте этот пример:

Примечание:

Является ли тот факт, что rawQuery() менее безопасен, чем query(), потому что метод query() использует предварительно скомпилированные инструкции, которые более безопасны, чем "сырые" операторы. Но всегда вы можете (должны) использовать заполнители, которые значительно повышают безопасность заявления, поскольку основная защита от SQL инъекций и операторов становится намного более понятной для человека.

Ответ 2

Это вроде поздно, но я думал, что другие, которые ищут, могут извлечь из этого выгоду:

db.query() метод поддерживает LEFT OUTER JOIN AND INNER JOIN через его аргумент table, поэтому вам действительно не нужно использовать SQLiteQueryBuilder для этого. Кроме того, это проще и довольно быстро.

Этот метод широко используется в Исходный код приложения Google I/O 2015.

A Быстрый пример (константы String для краткости опущены):

Cursor cursor = db.query(NoteContract.Note.TABLE_NAME 
+ " LEFT OUTER JOIN authors ON notes._id=authors.note_id", projection, selection, 
selectionArgs, null, null, "notes._id");

Ключ находится в первом аргументе db.query().

В настоящее время поддерживаются только LEFT OUTER JOIN и INNER JOIN, чего вполне достаточно для большинства приложений.

Я надеюсь, что этот ответ поможет другим, кто ищет это.

Ответ 3

Да, вы можете использовать query() вместо rawQuery(), учитывая одно предположение - в таблицах, которые вы соединяете, нет двух одинаковых имен столбцов.

Если этот критерий заполнен, вы можете использовать этот ответ fooobar.com/questions/66747/...

Ответ 4

В соответствии с комментарием SharpEdge и после попытки более сложного примера, основанного на ответе Nimrod Dayan, здесь приведен более сложный пример.

Используются 4 соединения, также используется сгенерированный столбец. Он использует выражение (вычитает временные метки), а затем использует это в предложении WHERE.

В принципе, метод заключается в том, чтобы добавить предложения соединения к строке имени таблицы (SQLite затем перемещает это для вас после столбцов).

DBConstants.SQL????? разрешен к соответствующему SQL, например. DBConstants.SQLISNOTNULL разрешает IS NOT NULL

DBConstans.CALCULATED????? - это имена вычисляемых столбцов.

DB????TableConstants.????_COL разрешает имена столбцов (.._FULL разрешает table.column, например, чтобы избежать неоднозначных столбцов _ID).

Метод (getToolRules) выглядит следующим образом: -

public Cursor getToolRules(boolean rulesexist,
                               int minimumruleperiodindays,
                               int minimumbuycount) {

        String columns[] = new String[] {
                "0 " + DBConstants.SQLAS + DBConstants.STD_ID,
                DBProductusageTableConstants.PRODUCTUSAGE_PRODUCTREF_COL,
                DBProductusageTableConstants.PRODUCTUSAGE_AISLEREF_COL,
                DBProductusageTableConstants.PRODUCTUSAGE_COST_COL,
                DBProductusageTableConstants.PRODUCTUSAGE_BUYCOUNT_COL,
                DBProductusageTableConstants.PRODUCTUSAGE_FIRSTBUYDATE_COL,
                DBProductusageTableConstants.PRODUCTUSAGE_LATESTBUYDATE_COL,
                DBProductusageTableConstants.PRODUCTUSAGE_ORDER_COL,
                DBProductusageTableConstants.PRODUCTUSAGE_RULESUGGESTFLAG_COL,
                DBProductusageTableConstants.PRODUCTUSAGE_CHECKLISTFLAG_COL,
                DBProductusageTableConstants.PRODUCTUSAGE_CHECKLISTCOUNT_COL,

                "(" +
                        DBProductusageTableConstants.PRODUCTUSAGE_LATESTBUYDATE_COL +
                        "- " +
                        DBProductusageTableConstants.PRODUCTUSAGE_FIRSTBUYDATE_COL +
                        " / (86400000)" +
                        ") " + DBConstants.SQLAS + DBConstants.CALCULATED_RULEPERIODINDAYS,

                DBProductsTableConstants.PRODUCTS_NAME_COL,

                DBAislesTableConstants.AISLES_NAME_COL,
                DBAislesTableConstants.AISLES_ORDER_COL,
                DBAislesTableConstants.AISLES_SHOPREF_COL,

                DBShopsTableConstants.SHOPS_NAME_COL,
                DBShopsTableConstants.SHOPS_CITY_COL,
                DBShopsTableConstants.SHOPS_ORDER_COL,

                DBRulesTableConstants.RULES_ID_COL_FULL +
                        DBConstants.SQLAS + DBRulesTableConstants.RULES_ALTID_COL,
                DBRulesTableConstants.RULES_AISLEREF_COL,
                DBRulesTableConstants.RULES_PRODUCTREF_COL,
                DBRulesTableConstants.RULES_NAME_COL,
                DBRulesTableConstants.RULES_USES_COL,
                DBRulesTableConstants.RULES_PROMPT_COL,
                DBRulesTableConstants.RULES_ACTON_COL,
                DBRulesTableConstants.RULES_PERIOD_COL,
                DBRulesTableConstants.RULES_MULTIPLIER_COL

        };
        String joinclauses = DBConstants.SQLLEFTJOIN +
                DBProductsTableConstants.PRODUCTS_TABLE +
                DBConstants.SQLON +
                DBProductusageTableConstants.PRODUCTUSAGE_PRODUCTREF_COL + " = " +
                DBProductsTableConstants.PRODUCTS_ID_COL_FULL + " " +

                DBConstants.SQLLEFTJOIN +
                DBAislesTableConstants.AISLES_TABLE +
                DBConstants.SQLON +
                DBProductusageTableConstants.PRODUCTUSAGE_AISLEREF_COL + " = " +
                DBAislesTableConstants.AISLES_ID_COL_FULL +

                DBConstants.SQLLEFTJOIN +
                DBShopsTableConstants.SHOPS_TABLE +
                DBConstants.SQLON +
                DBAislesTableConstants.AISLES_SHOPREF_COL + " = " +
                DBShopsTableConstants.SHOPS_ID_COL_FULL +

                DBConstants.SQLLEFTJOIN +
                DBRulesTableConstants.RULES_TABLE +
                DBConstants.SQLON +
                DBProductusageTableConstants.PRODUCTUSAGE_PRODUCTREF_COL + " =  " +
                DBRulesTableConstants.RULES_PRODUCTREF_COL +
                DBConstants.SQLAND +
                DBProductusageTableConstants.PRODUCTUSAGE_AISLEREF_COL + " = " +
                DBRulesTableConstants.RULES_AISLEREF_COL
                ;
        String ruleexistoption = DBRulesTableConstants.RULES_ID_COL_FULL;
        if (rulesexist) {
            ruleexistoption = ruleexistoption + DBConstants.SQLISNOTNULL;
        } else {
            ruleexistoption = ruleexistoption + DBConstants.SQLISNULL;
        }

        String whereclause = DBProductusageTableConstants.PRODUCTUSAGE_BUYCOUNT_COL +
                " = ?" +
                DBConstants.SQLAND + ruleexistoption +
                DBConstants.SQLAND +
                "(" + DBConstants.CALCULATED_RULEPERIODINDAYS + " / ?) > 0" +
                DBConstants.SQLAND +
                DBProductusageTableConstants.PRODUCTUSAGE_BUYCOUNT_COL + " > ?";

        if (minimumbuycount > 0) {
            --minimumbuycount;
        }
        String[] whereargs = new String[] {
                "0",
                Integer.toString(minimumruleperiodindays),
                Integer.toString(minimumbuycount)
        };
        return db.query(DBProductusageTableConstants.PRODUCTUSAGE_TABLE + joinclauses,
                columns,whereclause,whereargs,null,null,null);

    }

Базовый SQL, который был создан в SQLite Manager, используется в качестве руководства для построения метода (выглядит намного лучше, IMHO, чем SQL, извлеченный из курсора в отладке): -

Внимание! 0 AS _ID используется для включения курсора для использования CursorAdapter (то есть для CursorAdapters требуется столбец с именем _ID)

SELECT 

0 AS _id,
productusage.productusageproductref,
productusage.productusageaisleref,
productusage.productusageorder,
productusage.productusagecost,
productusage.productusagebuycount,
productusage.productusagefirstbuydate,
productusage.productusagelatestbuydate,
productusage.productusagerulesuggestflag,
productusage.productusagechecklistflag,
productusage.productusagechecklistcount,

/*********************************************************************************************************************************
 Calculate the period in days from between the firstbuydate and the latestbuydate 
*********************************************************************************************************************************/
(productusagelatestbuydate - productusagefirstbuydate) / (1000 * 60 * 60 * 24) AS periodindays,

products.productname,

aisles.aislename,
aisles.aisleorder,
aisles.aisleshopref,

shops.shopname,
shops.shopcity,
shops.shoporder,

rules._id AS rule_id,
rules.rulename,
rules.ruleuses,
rules.ruleprompt,
rules.ruleacton,
rules.ruleperiod,
rules.rulemultiplier

FROM productusage
LEFT JOIN products ON productusageproductref = products._id
LEFT JOIN aisles ON productusageaisleref = aisles._id
LEFT JOIN shops ON aisles.aisleshopref = shops._id
LEFT JOIN rules ON productusageaisleref = rules.ruleaisleref AND productusageproductref = rules.ruleproductref
WHERE productusagebuycount > 0 AND rules._id IS NULL AND (periodindays / 2)  > 0 AND productusage.productusagebuycount > 0

Ответ 5

public HashMap<String, String> get_update_invoice_getdata(String gen) {
    // TODO Auto-generated method stub
    HashMap<String, String> wordList;
    wordList = new HashMap<String, String>();
    Cursor cur_1 = ourDataBase
            .rawQuery(
                    "SELECT * FROM  Invoice i JOIN Client c ON i.Client_id=c.Client_id JOIN TAX t ON i.Tax_id=t.Tax_id JOIN Task it ON i.Task_id=it.Task_id WHERE i.Inv_no=?",
                    new String[] { gen });
    int intext = cur_1.getColumnIndex(C_ORG_NAME);
    int intext5 = cur_1.getColumnIndex(TA_NAME);
    int intext6 = cur_1.getColumnIndex(TA_RATE);
    int intext7 = cur_1.getColumnIndex(TA_QTY);
    int intext8 = cur_1.getColumnIndex(TA_TOTAL);

    if (cur_1.moveToFirst()) {

        do {
            wordList.put("Org_name", cur_1.getString(intext));
            wordList.put("client_id", cur_1.getString(2));
            wordList.put("po_number", cur_1.getString(4));
            wordList.put("date", cur_1.getString(3));
            wordList.put("dis_per", cur_1.getString(7));

            wordList.put("item_name", cur_1.getString(intext5));
            wordList.put("item_rate", cur_1.getString(intext6));
            wordList.put("item_cost", cur_1.getString(intext7));
            wordList.put("item_total", cur_1.getString(intext8));

        } while (cur_1.moveToNext());
    }

    return wordList;
}