SQLite загружает элементы из предыдущей группы, не фильтрует по внешнему ключу - PullRequest
0 голосов
/ 11 ноября 2018

База данных состоит из уровней, и каждый уровень состоит из нескольких тестов.

Уровень 1 состоит из 3 тестов

Уровень 2 имеет 10 тестов.И так далее ...

Уровень 1 в порядке, как и должно быть, есть 3 теста.

Когда я открываю уровень 2, он показывает мне тесты от 1 до 10, как и должно быть, НО проблема в 1 - 3 викторинах первые 3 викторины на самом деле с уровня 1 , а с викторины 4 до викторины 10 мой уровень 2 идет (где осталось 7 викторин).Где я забыл отфильтровать, или не правильно?

public class QuizDbHelper extends SQLiteOpenHelper {


.......skip here....

@Override
public void onConfigure(SQLiteDatabase db) {
    super.onConfigure(db);
    db.setForeignKeyConstraintsEnabled(true);
}

private void addJLPTLevel(JLPTLevel jlptLevel) {
    ContentValues cv = new ContentValues();
    cv.put(JLPTLevelsTable.COLUMN_NAME, jlptLevel.getName());
    cv.put(JLPTLevelsTable.COLUMN_JLPTLevel_ID, jlptLevel.getLevelID());
    db.insert(JLPTLevelsTable.TABLE_NAME, null, cv);
}

private void addQuizList(ListQuiz listQuiz) {
    ContentValues cv = new ContentValues();
    cv.put(QuizListTable.COLUMN_NAME, listQuiz.getName());
    cv.put(QuizListTable.COLUMN_JLPTLevel_ID, listQuiz.getLevelID());
    db.insert(QuizListTable.TABLE_NAME, null, cv);
}

private void addQuestion(Question question) {
    ContentValues cv = new ContentValues();
    cv.put(QuestionsTable.COLUMN_QUESTION, question.getQuestion());
    cv.put(QuestionsTable.COLUMN_OPTION1, question.getOption1());
    cv.put(QuestionsTable.COLUMN_OPTION2, question.getOption2());
    cv.put(QuestionsTable.COLUMN_OPTION3, question.getOption3());
    cv.put(QuestionsTable.COLUMN_OPTION4, question.getOption4());
    cv.put(QuestionsTable.COLUMN_ANSWER_NB, question.getAnswerNB());
    cv.put(QuestionsTable.COLUMN_QUIZ_LIST_ID, question.getListTest());
    db.insert(QuestionsTable.TABLE_NAME, null, cv);
}


public ArrayList<ListQuiz> getNListQuiz(int NListID) {
    ArrayList<ListQuiz> nQuizList = new ArrayList<>();
    db = getReadableDatabase();

    String selection = QuizListTable.COLUMN_JLPTLevel_ID + " = ? ";

    String[] selectionArgs = new String[]{String.valueOf(NListID)};

    Cursor c = db.query(
            QuizListTable.TABLE_NAME,
            null,
            selection,
            selectionArgs,
            null,
            null,
            null
    );

    if (c.moveToFirst()) {
        do {
            ListQuiz nQuizLevel = new ListQuiz();
            nQuizLevel.setId(c.getInt(c.getColumnIndex(QuizListTable._ID)));
            nQuizLevel.setName(c.getString(c.getColumnIndex(QuizListTable.COLUMN_NAME)));
            nQuizLevel.setLevelID(c.getInt(c.getColumnIndex(QuizListTable.COLUMN_JLPTLevel_ID)));
            nQuizList.add(nQuizLevel);
        } while (c.moveToNext());
    }
    c.close();
    return nQuizList;
}


public ArrayList<Question> getNLevelQuestions(int quizListID) {
    ArrayList<Question> questionList = new ArrayList<>();
    db = getReadableDatabase();

    String table = QuestionsTable.TABLE_NAME + "JOIN" + QuizListTable.TABLE_NAME +
            " ON " + QuizListTable._ID + "=" + QuestionsTable.COLUMN_QUIZ_LIST_ID;
    String[] columns = new String[]{
            QuestionsTable._ID + " AS " + QuestionsTable.TABLE_NAME + "_" + QuestionsTable._ID,
            QuestionsTable.COLUMN_QUIZ_LIST_ID,
            QuizListTable._ID + " AS " + QuizListTable.TABLE_NAME + "_" + QuizListTable._ID,
            QuizListTable.COLUMN_JLPTLevel_ID,
            QuizListTable.COLUMN_NAME
    };


    String selection = QuestionsTable.COLUMN_QUIZ_LIST_ID + " = ? ";

    String[] selectionArgs = new String[]{String.valueOf(quizListID)};

    Cursor c = db.query(
            QuestionsTable.TABLE_NAME,
            columns,
            selection,
            selectionArgs,
            null,
            null,
            null
    );

    if (c.moveToFirst()) {
        do {
            Question question = new Question();
            question.setId(c.getInt(c.getColumnIndex(QuestionsTable._ID)));
            question.setQuestion(c.getString(c.getColumnIndex(QuestionsTable.COLUMN_QUESTION)));
            question.setOption1(c.getString(c.getColumnIndex(QuestionsTable.COLUMN_OPTION1)));
            question.setOption2(c.getString(c.getColumnIndex(QuestionsTable.COLUMN_OPTION2)));
            question.setOption3(c.getString(c.getColumnIndex(QuestionsTable.COLUMN_OPTION3)));
            question.setOption4(c.getString(c.getColumnIndex(QuestionsTable.COLUMN_OPTION4)));
            question.setAnswerNB(c.getInt(c.getColumnIndex(QuestionsTable.COLUMN_ANSWER_NB)));
            question.setListTest(c.getInt(c.getColumnIndex(QuestionsTable.COLUMN_QUIZ_LIST_ID)));
            questionList.add(question);
        } while (c.moveToNext());
    }

    c.close();
    return questionList;
}
}

QuizContractor.java

package com.hfad.jlpt1quiz;

import android.provider.BaseColumns;

public final class QuizContract {

private QuizContract() {
}
public static class JLPTLevelsTable implements BaseColumns{
    public static final String TABLE_NAME = "test_level";
    public static final String COLUMN_NAME = "LevelName";
    public static final String COLUMN_JLPTLevel_ID = "LevelID";

}

public static class QuizListTable implements BaseColumns{
    public static final String TABLE_NAME = "quiz_list";
    public static final String COLUMN_NAME = "name";
    public static final String COLUMN_JLPTLevel_ID = "LevelID";
    //QuizListTable._ID to QuestionsTable.COLUMN_QUIZ_LIST_ID
}

public static class QuestionsTable implements BaseColumns {
    public static final String TABLE_NAME = "quiz_questions";
    public static final String COLUMN_QUESTION = "question";
    public static final String COLUMN_OPTION1 = "option1";
    public static final String COLUMN_OPTION2 = "option2";
    public static final String COLUMN_OPTION3 = "option3";
    public static final String COLUMN_OPTION4 = "option4";
    public static final String COLUMN_ANSWER_NB = "answer_nb";
    //It should be foreign key for QuizListTable._ID
    public static final String COLUMN_QUIZ_LIST_ID = "quiz_list_id";
}

}

Уровень теста

enter image description here

Контрольные списки

enter image description here

Контрольные вопросы

enter image description here

1 Ответ

0 голосов
/ 11 ноября 2018

Предполагается, что вы ожидаете, что определение внешнего ключа автоматически извлечет данные в соответствии с определенными внешними ключами. Это не будет иметь место. Все, что определяет внешний ключ, это добавляет ограничение (правило), которому нужно следовать, говоря, что для вставки строки в таблицу (дочерний), которая ссылается на другую таблицу MUST (если foreignKey Ограничения Включено это правда). Таким образом, вы должны JOIN таблицы ON ссылка для получения данных из обеих таблиц.

Предполагая, что у вас есть две таблицы

опросник который имеет;

  • столбец для id отдельного опросника (_id на картинке),
  • столбец для имени и
  • столбец для уровня (не уверен, почему идентификатор на вашей картинке, просто кажется, что число достаточно, так как на рисунке показано, что строки имеют одинаковый уровень)

и вопрос который имеет;

  • столбец для id отдельного вопроса
  • столбец, который ссылается на опросник (и, следовательно, уровень).

    • (минимальные столбцы включены для краткости / демонстрации)

Затем используйте следующую команду для заполнения таблиц: -

DROP TABLE IF EXISTS question;
DROP TABLE If EXISTS quizlist;

CREATE TABLE IF NOT EXISTS quizlist (ID INTEGER PRIMARY KEY, level INTEGER, name TEXT);
CREATE TABLE IF NOT EXISTS question (ID INTEGER PRIMARY KEY, question TEXT, quizlist_reference REFERENCES quizlist(id));

INSERT INTO quizlist (level,name) VALUES (1,'P 1'), (1,'P 2'),(1,'P 3'),(2,'P 4'),(2,'P 5'),(3,'P 6'),(3,'P 7');
INSERT INTO question (question, quizlist_reference) VALUES
    ('Q1',1),('Q2',6),('Q3',2),('Q4',4),('Q5',3),('Q6',1),('Q7',1),('Q8',1),('Q9',3),('Q10',3),('Q11',3),
    ('Q12',2),('Q13',4),('Q14',5),('Q15',3),('Q16',4),('Q17',6);

приведет к двум таблицам: -

викторина : -

enter image description here

вопрос : -

enter image description here

Как видно, уровень и название уровня не включены, данные собраны. Вместо этого, если вы выполнили запрос SELECT, используя (вопрос касается только данных, удобных для пользователя, это имя уровня и его уровень): -

SELECT question, name, level 
    FROM question 
        JOIN quizlist ON quizlist.id = quizlist_reference 
    ORDER BY question ASC;

Результат будет: -

enter image description here

  • Сортировка заметок (ORDER BY) по вопросам в данном случае не поможет.
  • Как видно по каждому вопросу, соответствующий уровень и название уровня теперь получаются.

Теперь просто выбрать все вопросы для уровня, все, что нужно, это предложение WHERE, например. WHERE level = 1 будет включено.

Итак, используя: -

SELECT question  
FROM question 
    JOIN quizlist ON quizlist.id = quizlist_reference 
WHERE level = 1 
ORDER BY question ASC;

Результатом будет: -

enter image description here

Аналогично: -

SELECT question  
FROM question 
    JOIN quizlist ON quizlist.id = quizlist_reference 
WHERE level = 2 
ORDER BY question ASC;

Результатом будет: -

enter image description here

Невозможно дать более конкретный ответ, не угадав, так как в вопросах нет указаний относительно внешних ключей, определений столбцов и т. Д. Таким образом, вам необходимо будет применять принципы, показанные соответствующим образом.

Применение запроса к Android

Обратите внимание, что для использования метода SQLiteDatabse query таблица вместе с JOIN предоставляется через первый параметр в виде строки.

Кроме того, если у вас есть одинаковые именованные столбцы (например, в приведенном выше примере в обеих таблицах есть столбец id ), курсор не содержит имя таблицы, поэтому у курсора будут столбцы с одинаковым именем и Метод getColumnIndex не обязательно будет получать правильные данные (я верю, что он получит последний такой столбец). Поэтому желательно давать столбцам конкретные имена с предложением AS (это как часть второго параметра).

Таким образом, используя адаптацию вашего кода для соответствия приведенным выше таблицам, метод, подобный следующему, может получить вопросы на определенном уровне: -

public ArrayList<Question> getQuestionsByLevel(int level) {
    ArrayList<Question> questionList = new ArrayList<>();
    db = getReadableDatabase();

    String table = QuestionsTable.TABLE_NAME + 
         " JOIN " + QuizListTable.TABLE_NAME + 
         " ON " + QuizListTable.COLUMN_ID  + "=" + QuestionsTable.COLUMN_QUESTIONS_QUIZ_LIST_REFERENCE;
    String[] columns = new String[]{
            QuestionsTable.COLUMN_ID + 
            " AS " + QuestionsTable.TABLE_NAME + "_" + QuestionsTable.COLUMN_ID, //<<<<<<<< make returned ID column (from questions table) unique name
            QuestionsTable.COLUMN_QUESTION,
            QuizListTable.COLUMN_ID + 
            " AS " + QuizListTable.TABLE_NAME + "_" + QuizListTable.COLUMN_ID, //<<<<<<<<<< make returned ID column (from quizlist table) unique name
            QuizListTable.COLUMN_LEVEL,
            QuizListTable.COLUMN_NAME
        };
    String selection = QuizListTable.COLUMN_QUIZ_LIST_LEVEL + "= ?";
    String[] selectionArgs = new String[]{String.valueOf(quizListID)};

    Cursor c = db.query(
            table,
            columns,
            selection,
            selectionArgs,
            null,
            null,
            null
    );
    ...............
  • Примечание Вышеуказанное предназначено только в качестве принципиального примера. Он не был проверен, поэтому может содержать некоторые ошибки. Дополнительно: -
    • Константы соответствуют тому, как они могут быть закодированы на основе того, что представляется конвенциями (не собирался тратить время на расшифровку предоставленного ограниченного кода)
    • Дополнительные столбцы добавлены для демонстрации, выше будет равно SELECT question.id AS question_id,question,quizlist.id AS quizlist_id, level, name FROM question JOIN quizlist ON quizlist.id = quizlist_reference WHERE level = 2
...