【问题标题】:Android SQLite using db.query() for JOIN instead of rawquery()Android SQLite 使用 db.query() 代替 rawquery()
【发布时间】:2013-04-06 14:54:11
【问题描述】:

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

提前致谢。

【问题讨论】:

    标签: android sqlite


    【解决方案1】:

    有没有办法使用 db.query() 而不是 db.rawquery()?

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

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

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

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

    注意:

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

    【讨论】:

      【解决方案2】:

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

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

      这种方法在Google I/O 2015 Schedule app's source code中被广泛使用。

      一个简单的例子(为简洁起见省略了字符串常量):

      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,对于大部分应用来说已经足够了。

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

      【讨论】:

      • 我希望有更多的例子..尽管如此 +1 以获得一些更新的信息。每个教程或示例都使用rawquery 或SQLiteQueryBuilder。
      【解决方案3】:

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

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

      【讨论】:

        【解决方案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);
        
            }
        

        在 SQLite 管理器中创建的基本 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
        

        【讨论】:

          【解决方案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;
          }
          

          【讨论】:

          • OP 专门要求提供一个使用查询而不是 rawQuery 的示例。另外,提供一些文本,而不仅仅是代码。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-04-28
          • 2012-05-16
          • 1970-01-01
          • 2012-02-08
          • 1970-01-01
          相关资源
          最近更新 更多