#java #android #sqlite #android-sqlite
#java #Android #sqlite #android-sqlite
Вопрос:
Задача, которую мне дали, — написать запрос, чтобы вернуть количество потерянных строк. Я достиг этого, но другая задача состоит в том, чтобы затем не использовать метод rawQuery для достижения того же результата с помощью метода запроса.
Проблема в том, что я получаю java.lang.Исключение IllegalStateException: недопустимые таблицы
Таблицы, которых существует 3, являются
- родительская таблица, в которой есть столбец _id и столбец name
- дочерняя таблица, в которой есть столбец _id, столбец name и столбец childtoparentlink, представляющий собой целое число, которое ссылается на родительскую таблицу.
- таблица друзей, в которой есть столбец _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. Спасибо, оба сработали, а также так просто. Также большое спасибо, поскольку я начинаю понимать гораздо больше.