Как я могу использовать этот запрос с помощью метода запроса (SQLiteDatabase.запрос)?

#java #android #sqlite #android-sqlite

#java #Android #sqlite #android-sqlite

Вопрос:

Задача, которую мне дали, — написать запрос, чтобы вернуть количество потерянных строк. Я достиг этого, но другая задача состоит в том, чтобы затем не использовать метод rawQuery для достижения того же результата с помощью метода запроса.

Проблема в том, что я получаю java.lang.Исключение IllegalStateException: недопустимые таблицы

Таблицы, которых существует 3, являются

  1. родительская таблица, в которой есть столбец _id и столбец name
  2. дочерняя таблица, в которой есть столбец _id, столбец name и столбец childtoparentlink, представляющий собой целое число, которое ссылается на родительскую таблицу.
  3. таблица друзей, в которой есть столбец _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("ttColumn: "   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);
    }
  

Как я могу выполнить запрос с помощью метода запроса вместо метода rawQuery, чтобы получить лучшие оценки?

Комментарии:

1. @forpas О, преподаватель, похоже, думает, что вы можете, поэтому я не думаю, что вы правы.

2. Смотрите ответ, который я опубликовал, с небольшим рассмотрением того, что делает метод запроса, это простое решение (ы, поскольку существует как минимум 2 способа).

3. @forpas вы не объясняете, что не так, вы только говорите это неправильно. Вы можете объяснить, что не так и почему не использовать трюк? Что насчет Android говорит, что если вы знаете запрос во время компиляции, вы всегда должны предпочесть Query, поскольку он проверяет запрос во время компиляции, а также генерирует более эффективный код ?

4. @srolyat в этом нет ничего плохого, это не уловка, это больше соответствует общей рекомендации, согласно которой rawQuery следует использовать только при необходимости, из-за ограничений и похвалы за то, что вы нашли часть того, почему это общая рекомендация.

5. @srolyat кроме того, удобные методы уменьшают вероятность простых ошибок, поскольку большая часть SQL построена так, чтобы строго придерживаться правильного синтаксиса, поэтому порядок предложений ключевых слов четко определен.

Ответ №1:

Ваша проблема в том, что метод запроса ожидает таблицу, поскольку затем генерирует SQL в соответствии с

 SELECT your_columns FROM the_table; 
  

Поскольку таблицы нет, она выдает недопустимое исключение таблицы.

Вы должны предоставить что-то, что удовлетворит предложению FROM , это не может быть ничем.

Вы можете обойти это несколькими способами, которые, я полагаю, являются тем, что домашнее задание пытается заставить вас выяснить / изучить.

Исправить 1

Вы могли бы предоставить одну из существующих таблиц, например, использовать

 csr = db.query(null,new String[]{sq_child_mismatches,sq_friend_mismatches},null,null,null,null,null,"1");
  
  • Обратите внимание на 8-й параметр, этот ОГРАНИЧИВАЕТ количество сгенерированных строк до единицы, поскольку для каждой строки в поддельной таблице будет сгенерирована строка.

Исправить 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 .

Комментарии:

1. Позвольте мне попробовать.

2. Спасибо, оба сработали, а также так просто. Также большое спасибо, поскольку я начинаю понимать гораздо больше.