mysql true/false/ mc questions table - mysql

I'm new to mysql but I am trying to make a quiz website as a pet project in php and store questions and answers in mysql. I want to have multiple choice and true and false questions for now. What would be the best way to do this. Should I create one table or two for the types of question. Any tips on how to write this?

I don't think it is a good idea to use one table.
I would say creating 2 tables will be good. Your question is light compare to what you intend to build. But if I guess right you will want to print result after submit... Then comes the answers table. If you are not using cookies, then "participant" should have a table too methinks.
Goodluck on your project it's a good start.

I would like to propose 3 tables.
1) Table with information about question and its type
2) Table for storing TF and question id
3) table for storing multiple choice options and question id
1) challenge_question table:
id
challenge_id
question (text of the question)
required (some questions will be required to be displayed per each challenge)
question_type (here I indicate what type of question: Mult. choice, T/F)
2) challenge_question_mc (multiple choice)
question_id = FK/PK to challenge_question
option = text of the option
is_correct = Boolean to indicate the answer
3) challenge_question_tf (true or false)
question_id = FK/PK to challenge_question
is_correct = Boolean

If you want both true/false and multiple choice questions (and don't want separate tables for each type of question) you could make the following three tables.
Question:
QuestionId: int unsigned primary key
Text: varchar
Answer:
AnswerId: int unsigned primary key
Text: varchar
QuestionAnswer:
QuestionId: int unsigned
AnswerId: int unsigned
IsCorrect: boolean
When you want to display the possible answers to a question you can JOIN the last two tables:
SELECT Answer.AnswerId, Answer.Text FROM Answer JOIN QuestionAnswer ON
Answer.AnswerId = QuestionAnswer.AnswerId WHERE QuestionId = ?
And if you want to check whether a given answer is correct you can use:
SELECT IsCorrect FROM QuestionAnswer WHERE QuestionId = ? AND AnswerId = ?
which will return 1 for the correct answer and 0 for wrong ones.
You can reuse rows in the Answer table if you don't want to create a new set of e.g. true/false answers for each question. Just make sure to connect questions with possible answers in the QuestionAnswer table and mark the combinations as true or false (1 = true, 0 = false).
If you don't care about reusing possible answers in different questions I guess it would suffice with two tables if you merged Answer and QuestionAnswer into a single table.
You might want some other tables later on if you want to separate the questions to specific quizzes. That could be achieved by making a Quiz table with QuizId and Name:
QuizId: int unsigned primary key
Name: varchar
and another table QuizQuestion where you tie QuizId and QuestionId together:
QuizId: int unsigned
QuestionId: int unsigned
Then you can use JOIN on the tables to get the questions of a specific quiz.

Related

MySQL: modeling for 90 yes or no questions survey with statistics support

I'm trying to design MySQL tables for survey.
The survey is composed of 6 sets of questions, 15 questions for each set, so total 90 questions. The questions and the order of questions are not gonna be changed, and there are some possibility for new set of questions(also 15 questions per set) to be added.
They are all 'yes or no' questions so the answers will be saved as true or false in boolean way.
I also save sex, nationality, age of users for statistics.
I wanna get the percentage of the same answers between two users.
I wanna get the percentage of the same answers between one person and majority(majority is the answer of more than 50%).
I wanna get the statistics of yes or no per question by combination of sex, nationality, age. For example, 66% answered yes for question no.11 or 12% of Korean women answered no for question no.86
So I made a table to support all those features
questions table
q_id PK(1 to 90)
q_text VARCHAR(100)
users table
u_id PK
sex TINYINT
nationality VARCHAR(20)
age TINYINT UNSIGNED
q_1 TINYINT
q_2 TINYINT
...
q_90 TINYINT
Is it okay to have 94 columns in one table? I'm afraid the number of columns will increase as I add some questions sets. So I splited answers to set table
set1 table
s_id PK
u_id users_table
q_1 TINYINT
q_2 TINYINT
...
q_15 TINYINT
set2 table
s_id PK
u_id users_key
q_16 TINYINT
q_17 TINYINT
...
q_30 TINYINT
and so on. I now have 6 set tables and I now can add new table if I add new set.
I searched a little about this and I saw that it would be better if I have a separate table for answers
answer table
a_id PK
u_id users_key
q_no question number(1~90)
answer TINYINT
I'm afraid that answers table may grow too big because answers table get 90 rows per user.
I'm really not sure which design is better. I've searched stackoverflow for answers but I couldn't find appropriate answer for yes or no survey.
Creating all those columns q_x is crazy, you just need to create a table called question_set with all the question like :
s_id PK
s_type (you can put 1, 2, 3 for set group)
q_id FK(questions)
You should normalize your table, putting all those columns will sooner than later create you problems. In the case you need to denormalize it is better to create views for that.
I would rather use foreign keys to make it more flexible.
So I would create
set_table
set_id PK
set_name Text
question_table
question_id PK
//This will help you put same question in multiple sets
question_set
set FK (set_table)
question FK (question_table)
user_table
user_id PK
user_name Text
sex Text
user_answer_table
user FK(user_table)
question FK(question_table)
answers Bool
Then you can write complex queries with joins to get all the metric you need. This will give you plenty of flexibility to add new questions, sets, users without the need to change the schema.

Best Practice: find row for unique id from multiple tables

our database contain 5+ tables
user
----------
user_id (PK) int NOT NULL
name varchar(50) NOT NULL
photo
--------
photo_id (PK) int NOT NULL
user_id (FK) int NOT NULL
title varchar(50) NOT NULL
comment
-------
comment_id (PK) int NOT NULL
photo_id int NOT NULL
user_id int NOT NULL
message varchar(50) NOT NULL
all primary key id's are unique id's.
all data are linked to http://domain.com/{primary_key_id}
after user visit the link with id, which is unique for all tables.
how should i implement to find what table this id belongs to?
solution 1
select user_id from user where user_id = {primary_key_id}
// if not found, then move next
select photo_id from photo where photo_id = {primary_key_id}
... continue on, until we find which table this primary key belongs to.
solution 2
create object table to hold all the uniqe id and there data type
create trigger on all the tables for AFTER INSERT, to create row in object table with its data type, which was inserted to a selected table
when required, then do select statement to find the table name the id belongs to.
second solution will be double insert. 1 insert for row to actual table with complete data and 2 insert for inserting unique id and table name in object table, which we created on step 1.
select type from object_table where id = {primary_key_id}
solution 3
prepend table name + id = encode into new unique integer - using php
decode id and get the original id with table name (even if its just as number type)
i don't know how to implement this in php, but this solution sounds better!? what are your suggestion?
I don't know what you mean by Facebook reference in the comments but I'll explain my comment a little further.
You don't need unique ID's across five DB tables, just one per table. You have couple of options how to create your links (you can create the links yourself can you?):
using GET variables: http://domain.com/page.html?pk={id}&table={table}
using plain URL: http://domain.com/{id}{table}
Depending on the syntax of the link you choose the function to parse it. You can for example use one or both of the following:
http://php.net/manual/en/function.explode.php
http://www.php.net/manual/en/function.parse-url.php
When you get the simple model working you may add encoding/decoding/hashing functions. But do you really need them? And in what level? (I have no experience in that area so I'll shut up now.)
Is it actually important to maintain uniqueness across tables?
If no, just implement the solution 3 if you can (e.g. using URL encoding).
If yes, you'll need the "parent" table in any case, so the DBMS can enforce the uniqueness.
You can still try to implement the solution 3 on top of that,
or add a type discriminator1 there and you'll be able to (quickly) know which table is referenced for any given ID.
1 Take a look at the lower part of this answer. This is in fact a form of inheritance.

Database design for preset/custom choice questions

So I have a HTML form where users can answer single-choice questions either by checkboxing one of the three preset responses, or writing a custom answer of their own.
While this is obviously a many-to-many relationship, I still cannot find a proper way to design database tables so as to handle both types (TEXT and BOOLEAN). My current quick-and-dirty solution is to hard-code a specific choice_id in the junction table for custom answers. I'm looking for a better pattern for this.
Have the following tables:
Table 1:Question
QuestionID (ID)
QuestionText (Text)
Table 2: Question Response
QuestionResponseId (ID)
QuestionResponseTypeId (References Question Response Type)
QuestionResponseDetailsId (References Question Response Details) - This should be used for text only values (Custom Answers)
QuestionResponse (Boolean)
Table 3: Question Response Type
QuestionResponseTypeId (Id)
Description (Text) -- Dictates if the answer is a boolean or a text field
Table 4: Question Response Details
QuestionResponseDetailsId (Id)
Description (Text) - Holds the text answer to the questions
When the following tables are populated you will have a structure that holds the question, the response of the question (text or boolean).
You could then filter on this to see only text based answers, for example:
SELECT * FROM QuestionResponse
INNER JOIN QuestionResponseDetails ON QuestionResponse.QuestionResponseDetailsId = QuestionResponseDetails.QuestionResponseDetailsId
WHERE QuestionResponse.QuestionResponseTypeId = 1
Where 1 is a Text based answer and 2 is a Boolean based answer (From the Question Response Type Table)
If I were you, I would do something like this:
Table Answers:
question_id INT(11)
answer_id INT(11)
preset_answer TINYINT(1) //1, 2, 3 for three answers
custom_answer VARCHAR(255)

Which database table is better?

I just want some advice, when creating a "Question" Table in the database, do I need store in the question number for each question or is this not needed as each question will have its own unique Id thanks to auto increment and that when students take the exam, the questions are going to appear in random order for each student so they can't copy answers.
In other words should the Question table be like this (Example 1):
QuestionId (int 11) auto increment PK //unique identifier for each question
QuestionNo (int 3) //the question number
QuestionContent (varchar 800) //the question itself
AnswerId (int 11) //Foreign key to AnswerId in Answer Table
Or should it be like this (example 2):
QuestionId (int 11) auto increment PK //unique identifier for each question
QuestionContent (varchar 800) //the question itself
AnswerId (int 11) //Foreign key to AnswerId in Answer Table
I think you answered your own question. The auto-increment PK field means that each question will have a unique ID number. The only reason you'd need to provide another question number field is if you need to be able to find questions according to some other numbering system that's already determined, or if the question number has some other significance.
I would make QuestionNo a field of a table that would join a test and a question. For example, I would have a Question_on_Test which would contain that field because it is only pertinent for a specific test revision and not pertinent on the question itself.
In your second design, if you remove a question from the database (for whatever reason) you will lose that question's ID number. That's something which may or may not be critical to your design.
I don't think it makes sense to have an AnswerID in the question table. This is assuming there could be several answers to one question (a one-to-many relationship). There is usually one right answer and several wrong answers.
If there is a just one answer per question, it doesn't need to be in a separate table.
Edit: And, since the questions can be randomly ordered, a question number is meaningless.
I think the Answer table should be:
int AnswerID (unique ID)
char AnswerChar (A, B, C, D, E)
int QuestionID (parent Question ID)
bool IsCorrect
text AnswerText

How to design a rating system which permits one vote per user considering the performance?

I am using Ruby on Rails\MySQL and I would like to implement a rating system with the following conditions\features considering a large amount of users and articles:
Each article have 3 rating criterias
Each criteria is a binary function (examples: good\bad, +1 \ -1, ...)
Each user can vote one only time per criteria and per article
I would like to know in those conditions what are the best approaches\techniques to design\think of the database (for exmple in UML) in order to ensure a optimal performance (response time of a database query, CPU overloading, ...).
P.S.: I think a rating system as that working for the Stackoverflow website.
Create a table for the ratings:
CREATE TABLE vote
(
userId INT NOT NULL,
articleId INT NOT NULL,
criterion ENUM('language', 'usefulness', 'depth') NOT NULL, -- or whatever
value BOOLEAN NOT NULL,
PRIMARY KEY (userId, articleId, criterion)
)
This will allow each user to cast at most one vote per article per criterion.
criterion has type enum which allows only three different criteria. This constraint is on metadata level: this means that if you want to add the criteria, you will have to change the table's definition rather than data.