SQLite从上一组加载项目,不按外键过滤

时间:2018-11-11 02:23:48

标签: android sqlite android-sqlite

数据库由各个级别组成,每个级别由多个测验组成。

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 :(得分:1)

您猜测外键的定义将根据定义的外键自动提取数据。事实并非如此。定义外键的全部作用是添加一个约束(规则),该约束必须遵循,即说要在表(子项)中插入引用另一个表必须的行(如果foreignKey Constraints Enabled为true)。因此,您必须加入 ON 以从两个表中获取数据。

假设您有两个表

测验列表,其中有;

  • 个人测验列表的 id 列(图片中的_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 列),则Cursor不包含表名,因此Cursor将具有相同名称的列和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