Android SQLite使用db.query()进行JOIN而不是rawquery()

时间:2013-04-06 14:54:12

标签: android sqlite

我有tableA,tableB和tableC 表A和表B由tableA.Id(PK)= tableB.tableAId(FK)连接 表B和tableC由ta​​bleB.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()来实现此查询?

提前感谢。

5 个答案:

答案 0 :(得分:19)

  

有没有办法使用db.query()而不是使用db.query()来实现此查询   db.rawquery()?

所以值得一提的是,rawQuery()是一个技巧。但也存在另一种方法。

query()方法用于在一个表上执行查询。 如何在SQLite中JOIN表使用SQLiteQueryBuilder以及使用setTables()方法加入的最佳方式。

因此我建议您使用提到的 SQLiteQueryBuilder 。但是对于需要仅分配原始语句的rawQuery()方法,它要复杂得多。

如果不知道如何开始,请查看以下示例:

注意:

rawQuery()的安全性低于query(),因为query()方法使用比“原始”语句更安全的预编译语句。但是,你总是可以(应该)使用占位符,这显着提高了声明的安全性,作为对SQL注入的主要保护,语句变得更加人性化。

答案 1 :(得分:19)

这有点晚了,但我认为其他正在寻找的人可能从中受益:

<div> <uib-tabset> <uib-tab ui-sref="principal.myplanManagement.myTimeTable" active="$state.current.name =='principal.myplanManagement.myTimeTable'"> <uib-tab-heading>Add MyTimeTable</uib-tab-heading> </uib-tab> <uib-tab ui-sref="principal.myplanManagement.myPlan" active="$state.current.name =='principal.myplanManagement.myPlan'"> <uib-tab-heading>Add MyPlan</uib-tab-heading> </uib-tab> <uib-tab ui-sref="principal.myplanManagement.myWDS" active="$state.current.name=='principal.myplanManagement.myWDS'"> <uib-tab-heading>Add MyWDS</uib-tab-heading> </uib-tab> </uib-tabset> <div ui-view></div> </div> 方法通过其db.query()参数本机支持LEFT OUTER JOIN AND INNER JOIN,因此您实际上不需要使用table来完成此操作。此外,它更容易,而且非常直接。

此方法广泛用于Google I/O 2015 Schedule app's source code

一个快速示例(为简洁起见,遗漏了字符串常量):

SQLiteQueryBuilder

密钥位于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,这对大多数应用来说已经足够了。

我希望这个答案可以帮助那些正在寻找这个的人。

答案 2 :(得分:1)

是的,您可以使用query()而不是rawQuery(),只需要一个假设 - 您要加入的表中没有两个相同的列名。

如果该条件已满,则可以使用此答案 https://stackoverflow.com/a/34688420/3529903

答案 3 :(得分:0)

根据 SharpEdge 的评论,在尝试了基于 Nimrod Dayan 的答案的更复杂的例子之后,这是一个更复杂的例子。

使用4个连接,也使用生成的列。它使用表达式(减去时间戳),然后在WHERE子句中使用它。

基本上,方法是将join子句追加到表名字符串(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);

    }

在SQLite Manager中创建的基本SQL,用作构建方法的指南(看起来好得多,恕我直言,比在调试中从游标中提取的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

答案 4 :(得分:-2)

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;
}