【问题标题】:How can I use this query with the query method (SQLiteDatabase.query)?如何将此查询与查询方法 (SQLiteDatabase.query) 一起使用?
【发布时间】:2019-04-21 21:13:46
【问题描述】:

我得到的任务是编写一个查询来返回孤立行的数量。我已经实现了这一点,但另一个任务是不使用 rawQuery 方法来使用查询方法来实现相同的结果。

问题是我得到 java.lang.IllegalStateException: Invalid tables

表,一共3张

  1. 具有_id 列和name 列的父表
  2. 子表有一个 _id 列、一个 name 列和一个 childtoparentlink 列,该列是一个链接到父表的整数。
  3. friend 表包含一个 _id 列、一个 name 列和一个friendtochildlink 列。

创建行并将行放入表中的 SQL,包括一些孤儿,就像

CREATE TABLE parent(_id INTEGER PRIMARY KEY,parentname TEXT);
CREATE TABLE child(_id INTEGER PRIMARY KEY,childname TEXT, childtoparentlink INTEGER);
CREATE TABLE friend(_id INTEGER PRIMARY KEY,friendname TEXT, friendtochildlink INTEGER);
INSERT INTO parent VALUES(null,'Parent A');
INSERT INTO parent VALUES(null,'Parent B');
INSERT INTO child VALUES(null,'Child A',1);
INSERT INTO child VALUES(null,'Child B',2);
INSERT INTO child VALUES(null,'Child X',10); -- orphan
INSERT INTO friend VALUES(null,'Friend A',1);
INSERT INTO friend VALUES(null,'Friend B',2);
INSERT INTO friend VALUES(null,'Friend X',100); -- orphan

在使用 rawQuery 时有效并给出正确值的查询是

SELECT 
    (
        SELECT count() FROM child 
            LEFT JOIN parent ON child.childtoparentlink = parent._id 
        WHERE parent.parentname IS NULL
    ) AS child_mismatches,
    (
        SELECT count() FROM friend 
            LEFT JOIN child ON friend.friendtochildlink = child._id 
        WHERE child.childname IS NULL
    ) AS friend_mismatches
  • 我得到两列,每列的值为 1(根据需要)。

我的实际代码是:-

public ArrayList<String> checkLinkIntegrity() {
    ArrayList<String> return_value = new ArrayList<>();
    String suffix = "_mismatches";
    String child_result_cl = TB_CHILD + suffix;
    String sq_child_mismatches = "(SELECT count() FROM " +
            TB_CHILD +
            " LEFT JOIN " + TB_PARENT +
            " ON " + TB_CHILD + "." + CL_CHILDTOPARENTLINK + " = " +
            TB_PARENT + "." + CL_PARENTID +
            " WHERE " + TB_PARENT + "." + CL_PARENTNAME + " IS NULL)" +
            " AS " + child_result_cl;
    String friend_result_cl = TB_FRIEND + suffix;
    String sq_friend_mismatches = "(SELECT count() FROM " +
            TB_FRIEND +
            " LEFT JOIN " + TB_CHILD +
            " ON " + TB_FRIEND + "." + CL_FRIENDTOCHILDLINK + " = " +
            TB_CHILD + "." + CL_CHILD_ID +
            " WHERE " + TB_CHILD + "." + CL_CHILDNAME + " IS NULL)" +
            " AS " + friend_result_cl;
    String full_query = "SELECT " + sq_child_mismatches + "," + sq_friend_mismatches;
    SQLiteDatabase db = this.getWritableDatabase();
    Cursor csr;
    Log.d("RAWQUERYSQL",full_query);
    csr = db.rawQuery(full_query,null);
    return_value.addAll(dumpCursorToStringArrayList(csr,"RAWQUERY"));

    // Fails invalid table
    csr = db.query(null,new String[]{sq_child_mismatches,sq_friend_mismatches},null,null,null,null,null);
    return_value.addAll(dumpCursorToStringArrayList(csr,"SECONDTRY"));
    csr.close();
    return return_value;
}

dumpCursortoStringArrayList 方法是:-

private ArrayList<String> dumpCursorToStringArrayList(Cursor csr, String tablename) {
    ArrayList<String> rv = new ArrayList<>();
    int original_position = csr.getPosition();
    csr.moveToPosition(-1);
    rv.add("Table: " + tablename);
    while (csr.moveToNext()) {
        rv.add("\tRow # " + String.valueOf(csr.getPosition() + 1));
        for (String column: csr.getColumnNames()) {
            rv.add("\t\tColumn: " + column + "\tvalue is: \t" + csr.getString(csr.getColumnIndex(column)));
        }
    }
    csr.moveToPosition(original_position);
    return rv;
}

如果我尝试 "" 而不是 null 例如,我会得到相同的错误。

如果我只使用我得到的 rawQuery

04-22 07:07:33.914 6271-6271/s.q001 I/RESULTS: Table: RAWQUERY
04-22 07:07:33.914 6271-6271/s.q001 I/RESULTS:  Row # 1
04-22 07:07:33.914 6271-6271/s.q001 I/RESULTS:      Column: child_mismatches    value is:   1
04-22 07:07:33.914 6271-6271/s.q001 I/RESULTS:      Column: friend_mismatches   value is:   1

这是使用

    ArrayList<String> results = DBOpenHelper.checkLinkIntegrity();
    for (String s : results) {
        Log.i("RESULTS",s);
    }

如何使用 query 方法而不是 rawQuery 方法运行查询以获得更好的分数?

【问题讨论】:

  • @forpas 哦,导师似乎认为你可以,所以我不认为你是对的。
  • 查看我发布的答案,稍微考虑一下查询方法的作用,这是一个简单的解决方案(至少有两种方法)。
  • @forpas 你没有解释什么是错的,你只是说错了。你可以解释什么是错的,为什么不使用技巧? Android 说 如果你在编译时知道查询,你应该总是更喜欢 Query,因为它会在编译时验证查询并生成更高效的代码
  • @srolyat 没有错,这不是一个把戏,它更多地遵循了一般建议,即 rawQuery 应该只在需要时使用,由于限制和荣誉您找到了为什么这是一般建议的部分原因。
  • @srolyat 另外,便捷的方法减少了简单错误的可能性,因为大多数 SQL 都是为了严格遵守正确的语法而构建的,因此关键字子句的顺序得到了很好的定义。

标签: java android sqlite android-sqlite


【解决方案1】:

您的问题是查询方法需要一个表,因为它会生成 SQL

SELECT your_columns FROM the_table; 

由于没有表,它会发出 Invalid Table 异常。

你必须提供满足FROM子句的东西,它不能什么都不是。

你可以通过几种方式解决这个问题,我想这就是作业试图让你确定/探索的内容。

修复 1

您可以提供存在的表之一,例如使用

csr = db.query(null,new String[]{sq_child_mismatches,sq_friend_mismatches},null,null,null,null,null,"1");
  • 注意第 8 个参数,这个LIMITs 生成的行数为 1,因为 fake 表中的每一行都会生成一行。

修复 2

或者 FROM 可以是子查询(见图),您可以使用子查询,例如你有一个

所以你可以使用:-

    csr = db.query(
            sq_child_mismatches, //<<<<<<<<<< the fake subquery
            new String[]{
                    sq_child_mismatches,
                    sq_friend_mismatches
            },
            null    ,null,null,null,null
    );
  • 在这种情况下,由于伪子查询返回单行/结果,因此不需要 LIMIT 子句。

【讨论】:

  • 让我试试看。
  • 谢谢你,既有效又如此简单。也非常感谢,因为我越来越了解。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-09-29
  • 2011-02-10
  • 1970-01-01
  • 2014-09-20
  • 1970-01-01
  • 1970-01-01
  • 2021-03-01
相关资源
最近更新 更多