-3

下面我有 4 个数据库表,Session、Question、Answer 和 Option_Type。

会话表:

SessionId  SessionName
1          AAA

问题表:

SessionId   QuestionId  QuestionContent       OptionId
1           1           What is 1+1 and 4+4   2
1           2           Does 2+2 = 4          26
1           3           What is 3+3 and 5+5   3

答案表:

AnswerId  SessionId QuestionId  Answer
1         1         1           B
2         1         1           C
3         1         2           Yes
4         1         3           A
5         1         3           C

Option_Type

OptionId OptionType
1        A-C
2        A-D
3        A-E
4        A-F

.... goes up to 24 where it goes up to A-Z

25       True or False
26       Yes or No

现在在这里的 jsfiddle 中,我创建了一个演示 html 表,您可以在这里看到

现在,如果您仔细查看 html 表格,您会意识到我要做的是在“不正确答案”列下显示不正确的答案。

所以我想做的是,例如对于问题 1,如果您查看数据库表,问题 1 的“OptionId”为 2,这意味着如果您在“Option_Type”表下查找“OptionId”,则“OptionType ",因为这个 OptionId 是 "AD"。所以选项是“A”、“B”、“C”和“D”。问题 1 的答案是“B”和“C”。所以我不想在表格中显示这些答案,因为它们是正确的,但我想显示其他选项“A”和“D”,因为它们不正确。

这有意义吗?我的问题实际上是如何不在“不正确答案”列下显示正确答案,而是在下面的代码中每个问题在此列下显示其他选项:

   $query = "SELECT q.SessionId, s.SessionName, q.QuestionId, q.QuestionContent, an.Answer, q.QuestionMarks 
   FROM Session s 
   INNER JOIN Question q ON s.SessionId = q.SessionId
   JOIN Answer an ON q.QuestionId = an.QuestionId AND an.SessionId = q.SessionId
   WHERE s.SessionName = ?
   ORDER BY q.QuestionId, an.Answer
   ";

   // prepare query
   $stmt=$mysqli->prepare($query);
   // You only need to call bind_param once
   $stmt->bind_param("s", $assessment);
   // execute query
   $stmt->execute(); 


       // This will hold the search results
    $searchQuestionId = array();
    $searchQuestionContent = array();
    $searchAnswer = array();
    $searchMarks = array();

    // Fetch the results into an array

   // get result and assign variables (prefix with db)
   $stmt->bind_result($dbSessionId, $dbSessionName, $dbQuestionId, $dbQuestionContent, $dbAnswer, $dbQuestionMarks);
      while ($stmt->fetch()) {
        $searchQuestionId[] = $dbQuestionId;
        $searchQuestionContent[] = $dbQuestionContent;
        $searchAnswer[] = $dbAnswer;
        $searchMarks[] = $dbQuestionMarks;
      } 

?>      

</head>

<body>

<form id="QandA" action="<?php echo htmlentities($_SERVER['PHP_SELF']); ?>" method="post">

<?php 

echo "<table border='1' id='markstbl'>
      <tr>
      <th class='questionth'>Question No.</th>
      <th class='questionth'>Question</th>
      <th class='answerth'>Incorrect Answer</th>
      <th class='answermarksth'>Penalty per Incorrect Answer</th>
      </tr>\n";
$previous_question_id = null;
$rowspans = array_count_values($searchQuestionId);
foreach ($searchQuestionContent as $key=>$question) {

    // removed logic, not necessary to set empty strings if you're skipping them

    echo '<tr class="questiontd">'.PHP_EOL;

    if ($previous_question_id != $searchQuestionId[$key]) {
        echo '<td class="questionnumtd" name="numQuestion" rowspan="'.$rowspans[$searchQuestionId[$key]].'">'.htmlspecialchars($searchQuestionId[$key]).'</td>' . PHP_EOL;
        echo '<td class="questioncontenttd" rowspan="'.$rowspans[$searchQuestionId[$key]].'">'.htmlspecialchars($question).'</td>' . PHP_EOL;
    }

    echo '<td class="answertd" name="answers[]">';
    echo $searchAnswer[$key];
    echo '</td>' ;
    echo '<td class="answermarkstd"><input class="individualMarks" name="answerMarks[]" id="individualtext" type="text" /></td>' . PHP_EOL;

    // moved this to the end
    if ($previous_question_id != $searchQuestionId[$key]) {
        $previous_question_id = $searchQuestionId[$key];
    }
}
        echo '</tr>';
        echo "</table>" . PHP_EOL;

        ?>

</form>

目前,上面的代码在“不正确答案”列下显示正确答案,而不是错误答案。

4

1 回答 1

2
  1. 创建一个潜在选项表:

    CREATE TABLE Answer_Options (Answer VARCHAR(5) NOT NULL PRIMARY KEY);
    
    INSERT INTO  Answer_Options VALUES
      ('A'), ('B'), ('C'), ('D'), ('E'), ('F'), ('G'), ('H'), ('I'), ('J'),
      ('K'), ('L'), ('M'), ('N'), ('O'), ('P'), ('Q'), ('R'), ('S'), ('T'),
      ('U'), ('V'), ('W'), ('X'), ('Y'), ('Z'),
    
      ('True'), ('False'),
      ('Yes'),  ('No')
    ;
    
  2. Option_Type创建一个将记录与这些选项相关联的表:

    CREATE TABLE OptionType_Options (
      OptionId TINYINT UNSIGNED NOT NULL,
      Answer   VARCHAR(5) NOT NULL,
      FOREIGN KEY (OptionId) REFERENCES Option_Type    (OptionId),
      FOREIGN KEY (Answer  ) REFERENCES Answer_Options (Answer  )
    );
    
    INSERT INTO OptionType_Options (OptionId, Answer)
      SELECT o.OptionId, a.Answer
      FROM Answer_Options a JOIN Option_Type o ON (
             o.OptionType LIKE '_-_' AND
             CHAR_LENGTH(a.Answer) = 1 AND
             a.Answer BETWEEN  LEFT(o.OptionType, 1)
                          AND RIGHT(o.OptionType, 1)
           ) OR (
             o.OptionType LIKE '% or %' AND
             a.Answer IN (
               SUBSTRING_INDEX(o.OptionType, ' or ',  1),
               SUBSTRING_INDEX(o.OptionType, ' or ', -1)
             )
           )
    ;
    
  3. 将该列定义Answer.Answer为这个新表的外键。

    ALTER TABLE Answer ADD FOREIGN KEY (Answer) REFERENCES Answer_Options (Answer);
    
  4. Option_Type可选择从现在多余的列中删除OptionType(但保留为人类可读的“名称/评论”类型元数据可能很有用):

    ALTER TABLE Option_Type DROP COLUMN OptionType;
    

    如果需要,仍然可以通过以下方式获得上一张表:

    SELECT   t.*,
             CONCAT_WS(
               IF(COUNT(*) > 2, '-', ' or '),
               MIN(o.Answer),
               MAX(o.Answer)
             ) AS OptionType
    FROM     Option_Type t JOIN OptionType_Options o USING (OptionId)
    GROUP BY OptionId
    
  5. 现在可以在可能的答案和正确的答案之间执行外连接,从交叉点之外的答案中确定不正确的答案:

    SELECT      Question.*,
                GROUP_CONCAT(o.Answer)                   AS  Possible_Answers,
                GROUP_CONCAT(a.Answer)                   AS   Correct_Answers,
                GROUP_CONCAT(NULLIF(o.Answer, a.Answer)) AS Incorrect_Answers
    FROM        OptionType_Options o JOIN Question USING (OptionId)
      LEFT JOIN Answer a USING (SessionId, QuestionId, Answer)
    GROUP BY    QuestionId
    

    sqlfiddle上查看。

  6. 要创建所需的输出:

    $stmt = $mysqli->prepare('
      SELECT      s.SessionId,  s.SessionName,
                  q.QuestionId, q.QuestionContent, q.QuestionMarks,
                  GROUP_CONCAT(o.Answer ORDER BY o.Answer SEPARATOR 0x1e),
                  COUNT(*)
      FROM        OptionType_Options o
             JOIN Question q USING ( OptionId)
             JOIN Session  s USING (SessionId)
        LEFT JOIN Answer   a USING (SessionId, QuestionId, Answer)
      WHERE       s.SessionName = ? -- SessionId would be better
              AND a.Answer IS NULL
      GROUP BY    s.SessionId, q.QuestionId
      ORDER BY    q.QuestionId
    ') or die($mysqli->error);
    $stmt->bind_param('s', $assessment) or die($stmt->error);
    $stmt->execute() or die ($stmt->error); 
    
    if (!$stmt->num_rows) die ('No results.');
    
    echo '
    <form id="QandA" method="post">
      <table border="1" id="markstbl">
        <tr>
          <th class="questionth">Question No.</th>
          <th class="questionth">Question</th>
          <th class="answerth">Incorrect Answer</th>
          <th class="answermarksth">Penalty per Incorrect Answer</th>
        </tr>
    ';
    
    $stmt->bind_result(
      $dbSessionId,  $dbSessionName,
      $dbQuestionId, $dbQuestionContent, $dbQuestionMarks
      $dbAnswers,    $rowspan
    );
    
    while ($stmt->fetch()) {
      echo 
        '<tr class="questiontd">', PHP_EOL,
          '<td class="questionnumtd" name="numQuestion" rowspan="',$rowspan,'">',
            htmlspecialchars($dbQuestionId),
          '</td>', PHP_EOL,
          '<td class="questioncontenttd" rowspan="'.$rowspan.'">',
            htmlspecialchars($dbQuestionContent),
          '</td>', PHP_EOL
        ;
    
        $first = true;
        foreach (explode(chr(0x1e), $dbAnswers) as $dbAnswer) {
          if (!$first) echo
        '<tr class="questiontd">', PHP_EOL;
    
          echo
          '<td class="answertd">',htmlspecialchars($dbAnswer),'</td>',
          '<td class="answermarkstd"><input',
            ' class="individualMarks"',
            ' name="answerMarks[',$dbAnswer,']"',
            ' id="individualtext"',
            ' type="text"',
          '/></td>', PHP_EOL,
        '</tr>';
    
          $first = false;
        }
    }
    
    echo '
        </table>
      </form>
    ';
    
于 2012-11-07T08:24:38.923 回答