I'm making a quiz game, and I want to make statistics of questions that has been answered wrong.
I have a database with 3 tables: Questions (all questions), Answers (the alternatives for each question), Games (stats about each game sessions).
Right now I'm thinking of two alternative ways to make a solution for this.
Save each question ID into an array, then save the array
into one record in MySQL at the end of the game.
Insert a new record with question ID into the table for each wrong
answer.
Which of these options would be the best approach to solve my problem? If I'm correctly, the last one will be easier when I'm gonna query the database to show questions that has been answered wrong. Any input or suggestions would be appreciated!
My advice is to save each answer given into a separate row, exactly for the reason you stated. Querying such a structure will be much easier than having multiple answers stored in a single row.
I would structure the tables as follows
Question
ID | Text | whatever else you may need
Answer
ID | QuestionID | Text | IsCorrect | whatever else you may need
Game
ID | User | StartTime | EndTime | whatever else you may need
Stats
ID | GameID | QuestionID | AnswerID | AnswerTime | whatever else you may need
This would need adjustments depending on the kind of analysis you're planning to do on it, but you get the idea.
Counting the number of times a wrong answers has been given would be as easy as
select t1.ID, count(*)
from Answer t1
join Stats t2
on t1.ID = t2.AnswerID
where t1.IsCorrect = 'N'
group by t1.ID
I am not sure I understood correctly your question. What follow is a possible solution for table statistics for answers if you want detailed information for each question / answer :
CREATE TABLE GAME_STATS (ID INT NOT NULL, ID_QUEST INT, ID_ANSWER INT, NUM INT);
ID is a sequence (you could omit this and make PK ID_QUEST, ID_ANSWER)
ID_QUEST refers to ID of table Questions
ID_ANSWER refers to ID of table Answers.
NUM is the number of times that answer has been selected.
You could consider to prepopulate the table for all possibile questions / answers (NUM = 0).
At the end of every answer, you should update the NUM (+1) for ID_QUEST, ID_ANSWERS.
If you want register statistics for each session / user, you should add appropriate columns (ex. id_session, and/or user_id).
In this case you can't prepopulate table. And you can register only wrong answers.
Related
I want to create an up vote and down vote system for my website where a unique user can vote up/down for one post and next time he only allow to opposite to get off from database and after that he again can up or down vote.
In this case I have:
users table :
id
name
debates table :
id
post
upvotes table:
id
user_id
debate_id
and similarly downvote table:
id
user_id
debate_id
Is that a good way to manage and track up vote and down vote concept?
I think, you can use a single table to track the votes and the structure could be something like this
Table : votes
id | user_id | debate_id | vote
Here, vote field could be tinyInt with defauld null.
And, in vote field, you just keep two different values depending on the vote type, for example, if a user up votes then insert a value of 1 in the vote field and for down vote, insert the value of 0. So, your table may look something like this
id | user_id | debate_id| vote
1 | 10 | 4 | 1 <-- up
2 | 11 | 4 | 0 <-- down
3 | 12 | 4 | 1 <-- up
In this case, two users with id = 10 and id = 12 up voted the post whose debate_id = 4 and another user with user_id = 11 down voted on the same post.
IN this case, you may find out how many up or down votes a post got by counting the vote field's value, for example, you may count for up votes for debate_id = 4 using something like this
$count = Debate::where('debate_id', '=', 4)->where('vote', '=', 1)->count();
Also, you may use something Query Scope, this is just an idea and it's not possible to make an answer which covers everything in this scope. You should start using some basic idea and if you stuck at a certain point, then you may ask specific questions with your code.
Also, I would like to mention that, if you find a user id in the votes table with a certain debate_id then this user has voted on this post and to find out the vote type, just check the vote field 1 or 0.
I would prefer to only have one table containing the votes, this could be done with an extra column such as is_downvote int(1).
It seems that you havn't tried much which is always a negative. For this scenario the Laravel Eloquent Documentation should be plenty to figure this out.
I would of written this as a comment but it's pretty lengthy now.
The question is not new in any way but it has a small twist to it.
My webpage is a membership page where users places bets. My idea is to create a new table for the users(with a naming convention like TABLE userBet+$userid) bets. User login information is already handled, my goal is now to save the bets of the user to a new table. A table which is created when users register. This will hopefully make score counting easier. Am I right or wrong? Could this be done in a better way? (Everything is done in PHP MySQL)
User registers -> Table for bets get created
"CREATE Table $userID ,id_bet, games, result, points"
And then matching this table against the correct result?
So again my questions: Is this a good way to do it? Is creating a table with the userID a smart thing to do?
EDIT
The bets is always 40 matches, which makes the tables Huge with columns and rows.
Should I make 40 Tables, one for each games instead? and put all users in there?
Am I right or wrong?
You are wrong. Dynamically altering your database schema will only make it harder to work with. There's no advantage you gain from doing so. You can do the same things by storing all bets within the same table, adding a column userid.
Posting as an answer due to author's request : )
Suggested database schema:
table matches:
id | name |
---------------
1 | A vs B |
table user_bets
id | user_id | match_id | points | result |
-------------------------------------------
1 | X | 1 | Y | Z |
Where match_id is related on matches.id
user_id = user.id
user_bets is only one table, containing all the info. No need of separate tables, as it was clear from the comments it's considered bad practice to alter the db schema via user input.
Before I ask my question, I just wanted to thank everyone that replied to my question yesterday -> Countdown using javascript.
Idea:
I created a quiz using php, but I would like to create a MySQL Database and having a table with all the questions, answers and multiple choice stored inside.
Issue:
Since the quiz is multiple choice, I don't know how to go about storing the multiple choice options in the table. Could I store the options and have each answer separated by a special character and let php get the string and separate the options?
Ex: Question: What is your favorite color? Options: Blue=Red=Purple=Yellow.(Database View)
What do you folks think is the best practice for something like this?
I think the best practice would be to use multiple tables. One for the question and one for answers. The answer table would contain question_id as well as a flag whether or not it is the correct answer
It could look like this
TABLE questions
FIELDS: id, text
TABLE answers
FIELDS: id, question_id, text, correct
The problem with using one field for all the answers is that you could accidently use the character you use for splitting inside the text of an answer
simply, create two tables:
questions
question_id, question
answers
answer_id, question_id, answer
Now, you can link these two tables using question_id
There are a couple of ways around this :
The "proper" way is to create another table ( so that you have a table called "questions", each of which have a unique id, and another called "answers", where each has the question id )
The "simple" way, which is to use JSON ( see json_encode and json_decode ) which takes care of using special characters etc in a field
You'd have a questions table, like this:
id | question
0 Do you even lift?
id would be INT(11) PRIMARY_KEY AUTO_INCREMENT while question would just be TEXT. Then, you would have an answers table:
id | question_id | answer
0 0 Yes
1 0 No
2 0 Maybe
Here, question_id refers to the ID of the question in the questions table. These answers all belong to one question. This is called a Has many relationship, as one question has many answers.
This is how its usually done. Implementing it is not that hard, even if you're not using a framework (most of them do the work for you).
Hope this helps
Tables:
quiz
quiz id (pk)
quiz info (other columns)
questions
question id(pk)
quiz id
question text
answers
answer id(pk)
question id
answer text
To display a given question do a join on the quiz, question and answers.
EDIT: You could either add a column for 'right/wrong answer (0/1)' or have another table:
solutions
solution id(pk)
question id
answer id
I didn't put the 'correct answer' in the answers table as that's not good normalization.
There could be many possible schema designs for this but my suggestion is like this:
Don't ever store values separated by comma on the tables.
This table holds the quizzes.
Quiz Table
QuizID (PK)
other columns..
This holds the questions for every quiz.
Question Table
QuestionID (PK)
QuestionDetail
QuizID (FK)
other columns...
This holds the answers.
Answer Table
AnswerID (PK)
AnswerDetail
This holds the correct answer for every question on each quiz or in other words, this is the answer key.
Question_Answer_Correct Table
QuestionID (FK) -- also a compound primary key with AnswerID
AnswerID (FK)
This contains list of users.
User Table
UserID (PK)
UserName
other columns...
This contains answer of users on a specified question. There is no QuizID here since the questions are already connected on the quiz table.
User_Answers Table
UserID (FK)
QuestionID (FK)
AnswerID (FK)
Let's say that I've got a table, like that (id is auto-increment):
id | col1 | col2
1 | 'msg'| 'msg'
2 | 'lol'| 'lol2'
3 | 'xxx'| 'x'
Now, I want to delete row number 2 and I get something like this
id | col1 | col2
1 | 'msg'| 'msg'
3 | 'xxx'| 'x'
The thing is, what I want to get is that:
id | col1 | col2
1 | 'msg'| 'msg'
2 | 'xxx'| 'x'
How can I do that in the EASIEST way (my knowledge about MySQL is very poor)?
You shouldn't do that.
Do not take an auto-incremented unique identifier as an ordinal number.
The word "unique" means that the identifier should be stuck to its row forever.
There is no connection between these numbers and enumerating.
Imagine you want to select records in alphabetical order. Where would your precious numbers go?
A database is not like an ordered list, as you probably think. It is not a flat file with rows stored in a predefined order. It has totally different ideology. Rows in the database do not have any order. And will be ordered only at select time, if it was explicitly set by ORDER BY clause.
Also, a database is supposed to do a search for you. So you can tell that with filtered rows or different ordering this auto-increment number will have absolutely nothing to do with the real rows positions.
If you want to enumerate the output - it's a presentation layer's job. Just add a counter on the PHP side.
And again: these numbers supposed to identify a certain record. If you change this number, you'd never find your record again.
Take this very site for example. Stack Overflow identifies its questions with such a number:
stackoverflow.com/questions/3132439/mysql-auto-decrementing-value
So, imagine you saved this page address to a bookmark. Now Jeff comes along and renumbers the whole database. You press your bookmark and land on the different question. Whole site would become a terrible mess.
Remember: Renumbering unique identifiers is evil!
I think there is no way to this directly. Maybe you can do "update" operation. But you must do it for all record after your deleted record. It is very bad solution for this.
Why using an auto-increment if you want to change it manually?
It is not good practice to change the value of an auto_increment column. However, if you are sure you want to, the following should help.
If you are only deleting a single record at a time, you could use a transaction:
START TRANSACTION;
DELETE FROM table1 WHERE id = 2;
UPDATE table1 SET id = id - 1 WHERE id > 2;
COMMIT;
However if you delete multiple records, you will have to drop the column and re-add it. It is probably not guaranteed to put the rows in the same order as previously.
ALTER TABLE table1 DROP id;
ALTER TABLE table1 ADD id INTEGER NOT NULL AUTO_INCREMENT;
Also, if you have data that relies on these IDs, you will need to make sure it is updated.
You can renumber the whole table like this:
SET #r := 0;
UPDATE mytable
SET id = (#r := #r + 1)
ORDER BY
id;
If we look at the stackoverflow website we have votes. But the question is what is the bestway to store who has voted and who has not. Lets also simplify this even more and say that we can only vote Up, and we can only Remove the Up vote.
I was thinking having the table to be in such form
question - Id(INT) | userId(INT) | title(TEXT) | vote(INT) | ratedBy(TEXT)
Thre rest is self explanitory but ratedBy is a Comma Seperated Id values of the Users.
I was thinking to read the ratedBy and compare it with the userId of the current logged in User. If he dosent exist in the ratedBy he can vote Up, otherwise he can remove his vote. Which in turn will remove the value from ratedBy
I think to make another table "vote" is better. The relationship between users and votes is n to n, therefore a new table should be created. It should be something like this:
question id (int) | user id (int) | permanent (bool) | timestamp (datetime)
Permanent field can be used to make votes stay after a given time, as SO does.
Other fields may be added according to desired features.
As each row will take at least 16B, you can have up to 250M rows in the table before the table uses 4GB (fat32 limit if there is one archive per table, which is the case for MyISAM and InnoDB).
Also, as Matthew Scharley points out in a comment, don't load all votes at once into memory (as fetching all the table in a resultset). You can always use LIMIT clause to narrow your query results.
A new table:
Article ID | User ID | Rating
Where Article ID and User ID make up the composite key, and rating would be 1, indicating upvote, -1 for a downvote and 0 for a removed vote (or just remove the row).
I believe your design won't be able to scale for large numbers of voters.
The typical thing to do is to create to tables
Table 1: question - Id(INT) | userId(INT) | title(TEXT)
Table 2: question - ID(INT) | vote(INT) | ratedBy(TEXT)
Then you can count the votes with a query like this:
SELECT t1.question_Id, t1.userId, t1.title, t2.sum(vote)
FROM table1 t1
LEFT JOIN table2 t2 ON t1.question_id = t2.question_id