moodle/mod/quiz/doc/databasetables.html
2005-06-29 09:47:44 +00:00

455 lines
18 KiB
HTML

<!DOCTYPE HTML PUBLIC>
<html>
<head>
<title>Database tables</title>
<meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
<!--LINK rel="Stylesheet" type="text/css" href="doc.css"-->
</head>
<body>
<h1>Database tables</h1>
<h2>Contents</h2>
<ul>
<a href='#structure'><li>Database structure</li></a>
<a href='#quiz_questions'><li>quiz_questions</li></a>
<a href='#quiz_newest_states'><li>quiz_newest_states</li></a>
</ul>
<h2>Database structure</h2>
<p>
The quiz data model has a fairly large pool of database tables, so the fist step
in explaining them is to provide some order. Conceptually it is possible to
distinguish between a <em>static</em> model, which allows defining quizzes and
questions, and a <em>runtime</em> model, which stores all the data that is
generated when users interact with the statically defined quizzes and questions.
Modifying the data in the tables from the <em>static</em> model is only possible
for users with teacher privileges (this constraint is <strong>not</strong>
imposed by the database, it is merely an observation). The data in the tables of
the <em>runtime</em> model is created when student users interact with quizzes.
Therefore these tables usually contain significantly more data than the ones
from the <em>static</em> model.
</p><p>
A further simplification is possible by ignoring the questiontype specific
tables. They are logical extensions to other tables and therefore are not
necessary for understanding the general basic model. However, some information
is provided for each questiontype specific table, namely which questiontype it
belongs to (although that should be clear from the name), which table it extends
and what the additional data is needed for.
</p><p>
Using these two criteria the list below puts some order into the collection of
tables.
</p>
<h3>Static model</h3>
<ul>
<li><a href="#quiz">quiz</a></li>
<li><a href="#quiz_categories">quiz_categories</a></li>
<li><a href="#quiz_answers">quiz_answers</a></li>
<li><a href="#quiz_grades">quiz_grades</a></li>
<li><a href="#quiz_question_versions">quiz_question_versions</a></li>
<li><a href="#quiz_questions">quiz_questions</a></li>
</ul>
<h3>Runtime Model</h3>
<ul>
<li><a href="#quiz_attempts">quiz_attempts</a></li>
<li><a href="#quiz_newest_states">quiz_newest_states</a></li>
<li><a href="#quiz_question_instances">quiz_question_instances</a></li>
<li><a href="#quiz_states">quiz_states</a></li>
</ul>
<h3>Questiontype specific tables</h3>
<ul>
<li><a href="#quiz_calculated">quiz_calculated</a></li>
<li><a href="#quiz_dataset_definitions">quiz_dataset_definitions</a></li>
<li><a href="#quiz_dataset_items">quiz_dataset_items</a></li>
<li><a href="#quiz_match">quiz_match</a></li>
<li><a href="#quiz_match_sub">quiz_match_sub</a></li>
<li><a href="#quiz_multianswers">quiz_multianswers</a></li>
<li><a href="#quiz_multichoice">quiz_multichoice</a></li>
<li><a href="#quiz_numerical">quiz_numerical</a></li>
<li><a href="#quiz_numerical_units">quiz_numerical_units</a></li>
<li><a href="#quiz_question_datasets">quiz_question_datasets</a></li>
<li><a href="#quiz_randomsamatch">quiz_randomsamatch</a></li>
<li><a href="#quiz_rqp">quiz_rqp</a></li>
<li><a href="#quiz_rqp_state">quiz_rqp_states</a></li>
<li><a href="#quiz_rqp_types">quiz_rqp_types</a></li>
<li><a href="#quiz_shortanswer">quiz_shortanswer</a></li>
<li><a href="#quiz_truefalse">quiz_truefalse</a></li>
</ul>
<h3>Redundant</h3>
<ul>
<li><a href="#quiz_attemptonlast_datasets">quiz_attemptonlast_datasets</a></li>
</ul>
<p>
These simplifications reduce the number of &quot;interesting&quot; tables to a
significantly smaller number, and still some of them are only necessary for
understanding very specific aspects of the quiz module. The diagram below shows
how the (selected) most important tables are linked to one another.
</p><p>
<img src="databasetables-01.gif" alt="Database Model" />
</p>
<a name="quiz"></a><h2>quiz</h2>
<p>
The quiz table contains the definition for all the quizzes. Each quiz belongs
to a course, reflected by the course id, has a name and a short descriptive text
(intro), an opening and a closing time and several fields that store the
settings of various quiz options, each of which is explained in the quiz help
that is linked to from the quiz settings page. <span style="color:red;">
One field that may require additional information is the optionsflag, which...
(maybe Gustav can add an explanation here?).
</span>
</p>
<p>
The quiz id is used extensively to identify records from various runtime tables,
reflecting the fact (surprise) that quizzes are the main players in the quiz
module.
</p>
<a name="quiz_categories"></a><h2>quiz_categories</h2>
<p>
Categories are provided as a way to organize questions. Each category has a name
and a descriptive text (info) and the sortorder as metadata. Categories allow
hierarchical nesting via the parent id and can be private or published, i.e.
they can be made available to teachers in other courses.
</p><p>
Since categories are simply a means for organising questions they are not vital
for undertanding how the quiz module works.
</p>
<a name="quiz_answers"></a><h2>quiz_answers</h2>
<p>
This table allows a common way to define one or more answers for each question.
It is not mandatory for a questiontype to make use of this table however. A
questiontype may choose to store it's answers in an entirely different way, or
even to calculate the correct answer on the fly.
</p><p>
The question id links each answer to a question, the sequence number field may
be used to store the order of the different answers, can be set to "0" though,
if the order is of no importance. The answer field stores whatever constitutes
an answer for the concerned questiontype (each questiontype can make whatever it
wants off it's answers), the fraction field stores the assigned score for the
question (range 0..1) and the feedback field allows defining some feedback, to
be displayed when the student's answer compares to the defined answer record.
</p>
<a name="quiz_grades"></a><h2>quiz_grades</h2>
<p>
The quiz_grades table merely stores a student's awarded grade for a quiz. Since
it is possible to allow several attempts on a quiz, the grade stored is
calculated depending on the quiz setting <code>grademethod</code>. This table
exists mainly for convenience, because the values of its fields can be
recalculated.
</p>
<a name="quiz_question_versions"></a><h2>quiz_question_versions</h2>
<p>
This feature is not finished and disabled. The table structure may still change.
</p>
<a name="quiz_questions"></a><h2>quiz_questions</h2>
<p>
This table constitutes the item or question bank, i.e. the repository of defined
questions. The <code>quiz_questions</code> table defines the common data for all
questions (and not least provides a unique id to manage them), which is extended
by other tables. E.g. the <code><a href="#quiz_answers">quiz_answers</a></code>
table allows to define an abitrary number of answers that are part of the
question. And many questiontype have their own extension of the
<code>quiz_questions</code> table.
</p><p>
Most fields are self explanatory, however, there are a few that require
additional explanation: the parent field is a means to provide support for
wrapped questions (e.g. the multianswer questiontype). When a question wraps
around any number of subquestions the subquestions will have their parent id
field set to the id of the main question, thus allowing the question to find all
its sub-questions (or wrapped questions). A side effect is that any question
with a parent id other than "0" is not shown in the list of questions that can
be added to a quiz. This side effect is also used for effectively hiding random
questions from the question list. Their parent field is simply set to their own
id.
</p><p>
It may seem strange then to also have a field called <code>hidden</code>,
but that serves a slightly different purpose. Hiding questions is first of all a
mechanism to &quot;delete&quot; questions without removing them from the
database and thus to restore or &quot;unhide&quot; them at a later stage. Also
the (unfinished and disabled) versioning feature uses the hidden field to
prevent older versions of a question from cluttering the user interface.
</p><p>
A question can also have a length. This defines how many question numbers are
required for this question. It is generally set to "1", but the description
questiontype, for example, sets it to "0", reflecting the fact that it doesn't
have a question number.
</p>
<a name="quiz_attempts"></a><h2>quiz_attempts</h2>
<p>
In the quiz_attempts table a record is created each time when a user starts an
attempt at a quiz. It is possible for a user to attempt a quiz several times,
therefore the number of the attempt is stored in the <code>attempt</code> field.
The <code>sumgrade</code> field records the (unscaled) grade for the attempt,
i.e. if the grades assigned to the questions add up to 8, but the maximum grade
for the quiz is set to 10, then the <code>sumgrades</code> field can contain 8
at maximum.
</p><p>
The <code>timestart</code> field is set to the current time when an attempt is
started and is never changed afterwards. The <code>timefinish</code> field is
set to "0" initially and to the current time when it is closed. This fact that
is exploited at several places in the code to determine whether an attempt
has been closed or not (i.e. closed = timefinish > 0). For all other
modifications of an attempt record the <code>timemodified</code> field should be
changed as well.
</p><p>
Finally, there are the <code>layout</code> and <code>preview</code> fields.
While the preview field simply denotes a teacher preview (i.e. an attempt by a
user with teacher privileges) that may be automatically deleted when the quiz is
previewed again, and which is not taken into account when viewing statistics,
the <code>layout</code> field is a little more complicated. It contains a comma
separated list of question ids, with a "0" denoting a pagebreak. In the case
where all questions on one page the comma separated list ends with ",0".
</p>
<a name="quiz_newest_states"></a><h2>quiz_newest_states</h2>
<p>This table exists only for efficiency reasons:</p>
<ol>
<li>Via its 'newest' and 'newgraded' fields it gives attempt.php
a way to quickly find the newest state
and the newest graded state for an attempt. It allows the
construction of SQL to select all the states that need to be loaded
on attempt.php or review.php.</li>
<li>Via its 'sumpenalty' field it gives quiz_apply_penalty() a quick
way for getting at the accummulated penalty that needs to be applied.
Without this field the penalties from all previous graded states
would have to be added up each time. Not a big deal actually because
this could be achieved with a single SQL query (using SUM) but this
field was introduced when we still had the multiplicative penalty
scheme around which would have been more difficult to recompute.</li>
</ol>
<p>This table was introduced in Moodle 1.5 and is not populated for all
states during the upgrade because on sites with a lot of existing
states that could take too long. Rather it is done whenever needed
by quiz_upgrade_states().</p>
<a name="quiz_question_instances"></a><h2>quiz_question_instances</h2>
<p>
Questions can have different grades assigned in different quizzes. These are
stored in the <code>quiz_question_instances</code> table. While, after a small
extension, this table could also fulfill the purpose of storing the order of the
questions in a quiz, this is currently still done in the <code>questions</code>
field in the <code>quiz</code> table.
</p>
<a name="quiz_states"></a><h2>quiz_states</h2>
<p>
States are saved for each interaction with a question. This allows to review the
complete history of a user's attempts on individual questions. The
<code>seq_number</code> field stores the order of this history, the
<code>answer</code> field stores a questiontype specific string unless the
questiontype stores its answers differently. The <code>event</code> field stores an integer, each of which is
defined as a named constant in the file <code>locallib.php</code>. E.g. values
can denote a saveing or a grading interaction amongst others.
</p><p>
Of further interest are the <code>grade</code>, <code>raw_grade</code> and
<code>penalty</code> fields. The <code>raw_grade</code> field stores the grade
that was achieved for the question scaled to the question's weight or grade as
assigned in the <code>quiz_question_instances</code> table. The <code>grade
</code> field stores the actual achieved grade after deduction of the penalty.
And in the <code>penalty</code> field the penalty for that state is saved. This
is different from the cumulative penalty, which is stored in the <code>
quiz_newest_states</code> table.
</p><p>
The <code>originalquestion</code> field is a construct that will be used by the
versioning code. The question ids in the states will be changed to the ids of
the new versions of the questions and the id of the question, which was used
for the actual attempt, will be stored in the <code>originalquestion</code>
field.
</p>
<a name="quiz_calculated"></a><h2>quiz_calculated</h2>
<p>
The <code>quiz_calculated</code> table is an extension to the
<code>quiz_questions</code> table by the calculated questiontype. However, it
would be more suitable to change that to be an extension of the
<code>quiz_answers</code> table, which, from a data perspective, is already
possible, since an answer id is stored in the <code>answer</code> field. The
questiontype code woud need some changes to take this into account, however.
</p>
<a name="quiz_dataset_definitions"></a><h2>quiz_dataset_definitions</h2>
<p>
The <code>quiz_dataset_definitions</code> table belongs to the abstract
datasetdependent questiontype, which is currently only used by the calculated
questiontype. It is an indirect extension to the <code>quiz_questions</code>
table, because the <code>quiz_question_datasets</code> table can link a question
to one or more datasets. Each dataset represents a variable, that is used either
in the questiontext or in the answer to a dataset dependent question.
</p>
<a name="quiz_dataset_items"></a><h2>quiz_dataset_items</h2>
<p>
Dataset items can be created for each dataset. The <code>quiz_dataset_items
</code> table stores these possible values for the variables defined in the
<code>quiz_dataset_definitions</code> table.
</p>
<a name="quiz_match"></a><h2>quiz_match</h2>
<p>
The <code>quiz_match</code> table belongs to the match questiontype and extends
the <code>quiz_questions</code> table. It is only used in the code for saving
matching questions and can therefore be considered redundant.
</p>
<a name="quiz_match_sub"></a><h2>quiz_match_sub</h2>
<p>
The <code>quiz_match_sub</code> table belongs to the match questiontype and
extends the <code>quiz_questions</code> table. It stores the pairs of questions
and answers (as strings) that need to be matched for a correct solution.
</p>
<a name="quiz_multianswers"></a><h2>quiz_multianswers</h2>
<p>
The <code>quiz_multianswers</code> table belongs to the multianswer questiontype
and is an extension of the <code>quiz_questions</code> table. It merely stores a
comma separated list of question ids in the <code>sequence</code> field, which
is important, because that's the only way to know which sub question belongs to
which position in the questiontext.
</p>
<a name="quiz_multichoice"></a><h2>quiz_multichoice</h2>
<p>
The <code>quiz_multichoice</code> table belongs to the multichoice questiontype
and is an extension of the <code>quiz_questions</code> table. The <code>layout
</code> field does not seem to be used, the <code>answers</code> field stores
the order of the answers (should be superceeded by the <code>seq_number</code>
field in the <code>quiz_answers</code> table) and the <code>single</code> field
is a flag signaling, whether only one option or multiple options can be chosen.
</p>
<a name="quiz_numerical"></a><h2>quiz_numerical</h2>
<p>
The <code>quiz_numerical</code> table belongs to the numerical questiontype
and is an extension of the <code>quiz_answers</code> table, defining a tolerance
value for each answer.
</p>
<a name="quiz_numerical_units"></a><h2>quiz_numerical_units</h2>
<p>
The <code>quiz_numerical_units</code> table is used by the numerical
questiontype and the calculated questionype. It extends the
<code>quiz_questions</code> table, defining an arbitrary number of units that
can be used in the responses.
</p>
<a name="quiz_question_datasets"></a><h2>quiz_question_datasets</h2>
<p>
The <code>quiz_question_datasets</code> table is used by dataset depenndent
questionypes (i.e. calculated) to link datasets to questions.
</p>
<a name="quiz_randomsamatch"></a><h2>quiz_randomsamatch</h2>
<p>
This extension to the <code>quiz_questions</code> table simply stores how many
shortanswer questions should be randomly chosen to build this randomsamatch
question.
</p>
<a name="quiz_rqp"></a><h2>quiz_rqp</h2>
<p>No information.</p>
<a name="quiz_rqp_states"></a><h2>quiz_rqp_states</h2>
<p>No information.</p>
<a name="quiz_rqp_types"></a><h2>quiz_rqp_types</h2>
<p>No information.</p>
<a name="quiz_shortanswer"></a><h2>quiz_shortanswer</h2>
<p>
The <code>quiz_shortanswer</code> table belongs to the shortanswer questiontype
and is an extension of the <code>quiz_questions</code> table. The answers field
stores a comma separated list of answer ids, which is redundant. The only
valuable piece of information contained in this table is the <code>usecase
</code> field, which is used to decide whether to do a case sensitive or case
insensitive comparison for grading.
</p>
<a name="quiz_truefalse"></a><h2>quiz_truefalse</h2>
<p>
An extension of the <code>quiz_questions</code> table the <code>quiz_truefalse
</code> table stores the answer ids for the true and for the false answers.
</p>
</body> </html>