Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

displaying incorrect answer from options

DB Table Structure:

Session Table (aka Exam Table)

SessionId(auto)  SessionName
137              XULWQ

Question Table:

SessionId  QuestionId  OptionId
137        1           5
137        2           2

Option_Table Table:

OptionId  OptionType
1         A-C
2         A-D
3         A-E
4         A-F
5         A-G
6         A-H
7         A-I
8         A-J
9         A-K
10        A-L
11        A-M
12        A-N
13        A-O
14        A-P
15        A-Q
16        A-R
17        A-S
18        A-T
19        A-U
20        A-V
21        A-W
22        A-X
23        A-Y
24        A-Z
25        True or False
26        Yes or No

Answer Table:

   AnswerId(auto) SessionId  QuestionId  Answer
   200            137        1           B
   201            137        1           D
   202            137        2           F
   203            137        2           A
   204            137        2           C

I want to create a page where I want it to display the incorrect answers per question.

I am thinking of doing it by retrieving the each question's option type, display the all the letter answers belonging to the option type, and then remove the correct answers from the letter answers so that it is left with incorrect answers only.

options array:

$option = array();

$option[1]= array(A,B,C);  
$option[2]= array(A,B,C,D);  
$option[3]= array(A,B,C,D,E);  

...

$option[23]= array(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);
$option[24]= array(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);
$option[25]= array(True,False);  
$option[26]= array(Yes,No);  

My question is that I need help after this section. How do I start retrieving the wrong answers after this array using mysqli/php and the database I currently have?

UPDATE:

Below shows the sql which displays the correct answers for each question:

  SELECT
      q.QuestionContent, 
      o.OptionType, 
      q.NoofAnswers, 
      GROUP_CONCAT(DISTINCT Answer ORDER BY Answer SEPARATOR '') AS Answer, 
      r.ReplyType, 
      q.QuestionMarks
    FROM Question q
    LEFT JOIN Answer an
      ON q.QuestionId = an.QuestionId
    LEFT JOIN Reply r 
      ON q.ReplyId = r.ReplyId 
    LEFT JOIN Option_Table o 
      ON q.OptionId = o.OptionId 
    group by q.QuestionContent

See SQL Fiddle with Demo

This returns the result:

|      QUESTIONCONTENT | OPTIONTYPE | NOOFANSWERS | ANSWER | REPLYTYPE | QUESTIONMARKS |
----------------------------------------------------------------------------------------
| Name these 2 flowers |        A-F |           2 |      C |  Multiple |             5 |
|         What is 2+2? |        A-D |           1 |    ABD |    Single |             5 |
like image 583
user1881090 Avatar asked Nov 04 '22 07:11

user1881090


1 Answers

Your problem is that, the way your Option_Table is designed, decoding the OptionType column to find out all the possible answers requires some nontrivial external knowledge.

(Indeed, you haven't provided enough information in your question for me to be sure exactly how to do that; I can make a guess for those OptionTypes which you've shown me, but I can't be sure if there are, or could be, others.)

It would be better to replace (or at least augment) that table with a simpler table which, for each OptionId, simply lists all the possible options, like this:

CREATE TABLE Options (
  OptionId INTEGER NOT NULL,
  OptionAnswer CHAR(1) NOT NULL,  -- or whatever type Answer.Answer has 
  PRIMARY KEY (OptionId, OptionAnswer)
);

INSERT INTO Options VALUES
  (1, 'A'), (1, 'B'), (1, 'C'),
  (2, 'A'), (2, 'B'), (2, 'C'), (2, 'D'),
  -- ...
  (25, 'T'), (25, 'F'),
  (26, 'Y'), (16, 'N');

Then you can find all the right and wrong answers for each question with a query like this:

SELECT
  q.QuestionContent, 
  q.NoofAnswers, 
  GROUP_CONCAT(DISTINCT Answer ORDER BY Answer SEPARATOR '') AS RightAnswers, 
  GROUP_CONCAT(DISTINCT
    CASE
      WHEN Answer IS NULL THEN OptionAnswer
      ELSE NULL
    END
    ORDER BY OptionAnswer SEPARATOR '') AS WrongAnswers, 
  r.ReplyType, 
  q.QuestionMarks
FROM Question q
LEFT JOIN Reply r 
  ON q.ReplyId = r.ReplyId 
LEFT JOIN Options o 
  ON q.OptionId = o.OptionId
LEFT JOIN Answer an
  ON q.QuestionId = an.QuestionId AND o.OptionAnswer = an.Answer
GROUP BY q.SessionId, q.QuestionId

Here's a demo of it on SQLize (slightly altered to skip columns not included in your example tables).


Edit: An alternative solution would be to construct the list of wrong answers in PHP. For example, if $row is an object (as returned e.g. by mysqli_fetch_object()) containing a single row from your original query, you could compute the wrong answers like this:

// Do this (preferably) before looping over the rows:
$specialOptionTypes = array(
    'Yes or No' => array( 'Y', 'N' ),
    'True or False' => array( 'T', 'F' ),
);

// Do this for each row:
if ( array_key_exists( $row->OptionType, $specialOptionTypes ) ) {
    $options = $specialOptionTypes[ $row->OptionType ];
} else if ( preg_match( '/^([A-Z])-([A-Z])$/', $row->OptionType, $match ) ) {
    $options = range( $match[1], $match[2] );
} else {
    // issue warning about unrecognized option type
    $options = array();
}
$right = str_split( $row->Answer );  // or explode() on a delimiter, if any
$wrong = array_diff( $options, $right );
$row->WrongAnswers = implode( '', $wrong );  // if you actually want a string

Here's a demo on ideone.com, based on your sample query output.

like image 89
Ilmari Karonen Avatar answered Nov 09 '22 06:11

Ilmari Karonen