15

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

提前致谢。

4

5 回答 5

21

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

因此,值得一提的是 rawQuery() 是一个把戏。但也存在另一种方法。

query() 方法旨在对一张表执行查询。但是如何JOIN在 SQLite 中创建表的最佳方法是使用SQLiteQueryBuildersetTables() 方法,您可以加入。

因此,我建议您使用提到的 SQLiteQueryBuilder。但是对于您只需要分配原始语句的 rawQuery() 方法,它会稍微复杂一些。

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

笔记:

rawQuery()不是query()因为query()方法使用比“原始”语句更安全的预编译语句更安全。但是你总是可以(应该)使用占位符来显着提高语句的安全性,作为防止SQL注入的主要保护,并且语句也变得更加易于阅读。

于 2013-04-06T14:59:07.060 回答
21

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

db.query()方法本身通过其参数支持LEFT OUTER JOINAND ,因此您实际上不需要使用它来完成它。它也更容易,而且非常直接。INNER JOINtableSQLiteQueryBuilder

这种方法在Google I/O 2015 Schedule app 的源代码中被广泛使用。

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

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

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

于 2015-11-18T11:20:39.557 回答
1

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

如果满足该标准,那么您可以使用此答案 https://stackoverflow.com/a/34688420/3529903

于 2016-02-21T19:59:47.937 回答
0

根据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);

    }

在 SQLite 管理器中创建的基本 SQL 用作构建方法的指南(看起来好得多,恕我直言,比在调试中从游标中提取的 SQL 更好)是:-

笔记!0 AS _ID用于使游标被a使用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
于 2017-01-23T05:27:45.447 回答
-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;
}
于 2014-05-12T04:23:29.957 回答