I have a webite where there is a discussion forum. All questions have unique ID and answers have also unique ID with a foreign key referencing to question ID.
I have a user logged in. Using ajax, I can send the data(upvote/downvote,QID/AID, username).But there are few problems.
Whenever user logs back in, I want that when he opens a question, his previous upvotes and downvotes should be displayed.
A user cannot upvote/downvote a same question multiple times. Like if he upvoted a question to +1, he can only downvote it, not upvote it again.
Solution according to me. I am thinking of maintaining a table where username is the primary key and another attribute is a list of all the upvotes and downvotes he has done. Example:
(username, array)
(baqir, up_A001 up_A050 down_Q011 up_Q123)
Whenever the user logs in, I take this array and make sure all the previous upvotes and downvotes of the user are as it is. If there is a new vote,I add it to the array.
Is there any better solution?
P.S. Not necceassary but my current database structure.
class Question(models.Model):
QID = models.CharField( default="",max_length=1000, primary_key=True)
title = models.CharField(max_length=30, default="")
description = models.CharField(max_length=1055, default="")
date = models.DateTimeField(default=datetime.now, blank=True)
username = models.CharField(max_length=6, default="")
votes = models.IntegerField(default=0)
approved = models.BooleanField(default=False)
def __str__(self):
return self.title
class Answer(models.Model):
AID = models.CharField(max_length=1000, default="", primary_key=True)
QID = models.ForeignKey(Question,on_delete=None)
description = models.CharField(max_length=1055, default="")
date = models.DateTimeField(default=datetime.now, blank=True)
username = models.CharField(max_length=6, default="")
votes = models.IntegerField(default=0)
approved = models.BooleanField(default=False)
def __str__(self):
return self.AID
I am using Django. And I basically want whatever stackoverflow has implemented for their voting of questions and answers.
What array people, what are you talking about? You make another table per Q/A or per user, or a table where you just link two things, i.e. user and Q/A and its votes where keys can be repeated (no primary keys for this table).
Any array-like thing is loss of time and energy and it is against good DB design rules anyway.
Example of table keeping votes:
Table votes:
UID | QID | AID | VOTE
So you connect each user with each question or answer he/she voted. QID or AID can be NULL. When you come to some question, you just check whether table votes has anything to say about it and answers tied to it. If current QID and UID match and you get result, you just act accordingly.
This has a potential of being slow if you have a lot of users, but essentially will work nice.
Second solution is to tie your question/answer with another table keeping in only users that did something (up/down voted it). This will make DB look messier but when your user comes to given Q and its answers you just check whether this table has something to say aboutsaid visitor or not. If I am not clear enough I repeat, new table per each Q and/or A.
You can apply same technique in reverse, i.e. connect user to a table that holds all Q/A that the user voted, which will perhaps be the best way of keeping order and efficiency. So each time the user comes to any Q page you check if he/she have any history for that Q.
No arrays, no nonsense. Just one extra request to check status for currently viewed Q/A.
CREATE TABLE QuestionVotes (
UID ..., -- User id
QID ..., -- Question id
vote ENUM('up', 'down'),
PRIMARY KEY(QID, UID) -- for finding voting status of a question
INDEX(UID, QID) -- if you need the votes by a user
) ENGINE=InnoDB; -- to get benefit of clustered PK
Ditto for AnswerVotes.
Upvote/downvote: See if the row exists, if not, create the row. If row exists, either delete the row or complain that the user is up/downvoting twice.
Do not use arrays. It will become too painful.
If Django won't let you have composite PRIMARY KEYs, abandon Django.
Do not have 1000-char keys in the table. Disk space and performance will suffer.
User can be only 6 characters. Not optimistic about scaling big?
Upvote and Downvote scenario can be handled using code,If the last vote is a upvote user have permission only to downvote, if the user downvote he has permission to upvote, but for keeping status as you told you can keep a history in a array.
the first approach suggested by Dalen seems best
make a separate table for storing votes, and before performing any up/downvote action, check if the user has done any similar action before.
In case he has done opposite action before, delete/deactivate his previous entry in table and make a new entry.
And in case he has already performed the same action for the question before, do nothing, as his up/downvote has already been accounted.
Making a table for such tasks is highly encouraged, as it will not only make your task easier, it will give you a lot more flexibility, like you can add a timestamp with each action to track history or you can hit a count query on the table to find the total actions performed on a question
Related
I saw a lot of questions here but no one fits with my problem. I'm trying to create an ER model scalable, and if I want to add more data don't break almost anything, so what I've trying to create is :
There are 2 types of users, let's say Admin and Worker, and they have different roles.
Admin can do a CRUD of questions, and also can create a room where the users can join to play together (this is just a name, something like Kahoot! does) but maybe is a good idea to create more attributes inside of it like, WHO is playing in this room, POINTS for everyone but let's talk it afterwards when I show you the design.
Ok the thing is, on my design I have :
Table User which contains :
_id
username
password
date_creation
This is a default one, but then I'm wondering how do I define the Role if it's an Admin or a Worker, something like isAdmin:true and then I check this Bool? Or I can create another table that is Role and connect it to User table?
But maybe I have to create a table for both, I mean there's an Admin which has a password, and some functionalities and then ther'es the user Worker which has another password and another functionalities.
Then I'd like to have the Question table where contains :
_id
question_name
answers[1,2,3,4]
correctAnswer or answers because it can be multi option chooser
topic
isExamQuestion
dificulty
Then the Room table should contains :
_id
name
capacity
type (game can be as a group or solo) that's why this attribute
exam (This should be a flag to know if this question is for an exam or not (It can be for EXAM or PRACTISE)
ranking (This is the top X from 1 to X)
don't think if I have to add the winner here because if I get the position 0 from ranking I get the winner...
There's a table named Topic as well, if my question have a topic then I can select the question by Topic. An example of Topic should be Math so user can do only exams or do tests with math questions.
_id
Name
Questions[...]
Then I have to store like a historic about what are the questions worker has answered correct and what did not, to make some statistics, but I need to store some historicals for Admin to see in this topic the average that Workers have failed more is : Question23 (for instance) something like that.
What I'm missing, could you try to help me to figure it out how to make this design better?
NOTE : I'm using Spring for server side, Angular for Frontend stuff, and Android for App, I can change anything to work faster/better with this database though.
EDIT
There's the flow of the game if you need more details and if I'm explainted wrong .
Admin flow
Create questions (with different kinds of answers like True/false, with a checkbos (single and multianswer), text, etc...)
Create a "game" where workers can join (This is mostly programming stuff) but it should be a room with attributes there, like id of the room, maxNumber, type (exam), and store historicals, theres also a type of game (for instance, images, videos, etc..)
See statistics about Workers it means see how many answers they answered correct, failed, see per topic (This is like joins and stuff, but the design has to be good done)
See historic of the exams that he did before with all of the information (participant, score, time, stuff)
And the Worker flow is
He can practise means that he's answering questions randomly or by topic (every single answer should be saved for statistics and to avoid repeat the ones he respons correct), also he can do exams (not multiplayer) just an option that Admin can check if the question is part of an exam or not.
And then the room stuff, he can join with the Id.
If you need further clarification let me know and I'll reply you as soon as possible.
In fact, your system has three logical parts (modules):
users module that contains user data and implements authentication and the authorization of user actions
questionnaires module that includes management of questions and answer
questionnaires history module that contains history by each user
Database design of those modules can look as follows
USER MODULE:
role - contains user roles in the system
id - unique identifier of the role
name - the role name, for example, admin, worker, etc.
user - contains users and information about roles were assigned to them
id - unique identifier of the user
username
password
role_id - identifier the role was assigned to the user
QUESTIONNAIRES MODULE:
topic - contains question themes
id - unique identifier of the theme
name - a name of the theme
question - contains questions
id - unique identifier of the question
topic_id - topic identifier of the question
text - content of the question
is_exam_question - exam question or not
type - type of answers (boolean, checkboxes or etc.)
difficulty
answer - contains all answers of questions
id - unique identifier of the answer
question_id - identifier of the question that contains the answer
text - content of the question
is_correct - flag that means the answer is true or false
room - contains information about rooms
id - unique identifier of the rum
name - name of the rum
capacity - the maximum number of workers which can join to the room
type - room type: group, solo or etc.
learing_type - room type: exam, practice or etc.
user_in_room - contains information about users which were joined to the room
user_id - identifier of the user that was joined to the room
room_id - identifier of the room
score - current score of the user in the room
HISTORY MODULE:
user_question_history - contains information about questions which were answered by the user
user_id - identifier of the user
room_id - identifier of the room where the user answered questions
question_id - identifier of the question that was answered by the user
score - user score by the question
user_answer_history - contains information about answers which were chosen by the user
user_id - identifier of the user
room_id - identifier of the room where the user answered questions
question_id - identifier of the question that was answered by the user
answer_id - identifier of the answer that was chosen the user
Usage of this schema gives the ability to build different reports. For example, you can display the result of all users by room
SELECT r.id,
r.name,
u.username,
ur.score
FROM room as r
LEFT JOIN user_in_room as ur ON ur.room_id = r.id
LEFT JOIN user as u ON u.id = ur.user_id
WHERE r.id = <id>
Or you can see detail information about answers of the user
SELECT
q.text,
a.text
FROM user_in_room as ur ON ur.room_id = r.id
LEFT JOIN user_question_history as uqh ON ugh.user_id = ur.user_id AND ugh.root_id = ur.room_id
LEFT JOIN question as q ON q.id = ugh.question_id
LEFT JOIN user_answer_history as uah ON uah.user_id = ugh.user_id AND uah.room_id = ugh.room_id AND uah.question_id = ugh.question_id
LEFT JOIN answer as a ON a.id = uah.answer_id
WHERE ur.room_id = <id> AND ur.user_id = <id>
Honestly, if you're certain you'll only have to possible types--both now and in the future--a simple bool isAdmin in your user table will work nicely. Everything else the admin does can be handled from the programming side. No need to clog up your db.
That said, if there's even a small chance you will have other types of users in the future, Maxim's answer is the way to go. That way, adding another role such as "Editor," for instance, is a simple as adding a record to the "Role" table. In fact, adding 1000 new types users is as simple as adding records to your "Role" table. Because you already have a table that you look to for the role, your code doesn't have to worry about all the possible types of users (which is a pain if you have a lot of them), only the ones it needs. The db is handling the rest.
One drawback to Maxim's answer is that it takes more work to implement in the db, and more work to view/update the role of the user.
To implement in the db, you need to create a whole extra table and make sure it's linked properly. This isn't hard, but, especially if you're new to dbs, is extra work that might not be worth it to you. This also means, from a maintenance side, that you have another table to keep tabs on. Not a huge deal, but, again, something to think about.
From the code side, this creates extra chores as well. For one, the user type is no longer directly in your users table--an ID is. This means when you want to know the name of the user type, you will have to either a) query the db for that user type based on the ID you have, or b) join the 2 tables, which can be tricky at times. Updating the role also has similar chores.
Again, these aren't huge problems, just things to think about. It might not be worth the extra work if you will only have two possible options.
So, in short, a boolean will work and is simple to implement, but is not scalable. Maxim's answer is quite scalable and makes future expansion easier, but somewhat harder to implement and maintain. You'll have to make the decision what you prefer.
You need a Profile table with one-to-many with User table, this way if another privelege you want to apply, just add new profile entry:
User table:
Id
Username
Fullname
Profile_id
...
Profile table:
Id
Name
Description
Exam and Question tables are related with many-to-many, to break it you will have a third table Question_Exam:
Question_Exam:
id_exam
Id_Question
Answer(provided)
Id_user(taking the exam)
IsCorrect(boolean, to avoid farther queries )
date
Topic and Question are one-to-many
Question table:
Id
Name
Answer(The correct one)
Id_topic
The other structure is fine.
I'm working in Django, but this question could apply to any database in general.
In my models, I have a UserProfile table. Another table UserQA contains a field for question_text and a field for question_answer. The problem with this model is that I would need a ManyToMany relation that has the overhead of two longints per question, and the question_text is duplicated for each user.
Basically, the requirements are:
Table of questions which users can contribute to by adding their own questions
Store 1 character answer (Y/N/O/Null) to each question for every user
2.1 Is there a way to extend this if I want some questions to have more complex answers?
This seemed like an easy problem, but I can't figure it out... The way I thought of doing it seems very inefficient, is there a better way?
Thanks!
You will need another model, can be Question. The final result would be something like:
class User(models.Model):
user_name = models.CharField(...)
class Question(models.Model):
question_text = models.CharField(...)
class UserAnswer(models.Model):
question = models.ForeignKey(Question)
user = models.ForeignKey(User)
answer = models.CharField(...)
If you want more complicated answers, like especific values, lists of values, you can create one more model:
class QuestionAlternative(models.Model):
question = models.ForeignKey(Question)
value = models.CharField(...)
And then redefine UserAnswer:
class UserAnswer(models.Model):
question = models.ForeignKey(Question)
user = models.ForeignKey(User)
answer = models.ForeignKey(QuestionAlternative)
With this, you will have the Questions in one place, one UserAnswer per question, and the QuestionAlternatives how many times they must exist. Does not worry about the ForeignKey fields, they are not overheads and they build beautiful, reusable structures.
Im designing a poll application, where the user creates one or several polls whith questions and predefined answers for each question, so far no problem, im thinking the easiest way to do this is with 3 tables:
Polls Table:
id title description
Questions table:
id poll_id question
Answers table:
id question_id answer
The problem is, the user may select a different behavior on the questioning flow of the poll, for example a normal poll will go from question 1 to question N (being N the final question), but in my case the user may want if the user choose answer 2 of question 4 to jump to question 7 and ignore the rest between them.
Im a bit confuse about how to store in database this behavior, any suggestions?
Looks like you need something similar to this:
Look at the construction of keys here:
The QUESTION is in identifying relationship with POLL and the resulting natural key provides not just uniqueness but ordering as well: QUESTION_NO can monotonically increase while keeping the same POLL_ID.
The equivalent effect is accomplished by ANSWER_NO in POSSIBLE_ANSWER.
The user can pick at most one answer for any given question. That's why ANSWER_NO is outside of the ACTUAL_ANSWER primary key.
On the other hand, USER_ID is kept inside the ACTUAL_ANSWER PK, to allow the same answer to be picked by more than one user.
Theoretically, there should be a key in QUESTION_TABLE on {POLL_ID, QUESTION_TEXT}, to prevent two different questions having the same text in the same poll. However, QUESTION_TEXT might be long and is potentially implemented as BLOB, which most DBMSes can't index or constrain by a key. The similar dilemma exists for POSSIBLE_ANSWER.ANSWER_TEXT.
If user skips a question, just omit the corresponding ACTUAL_ANSWER.
Answer > NextQuestion table
AnswerID NextQuestionID
Based on your answer, the next question is defined in here
Assuming I want to have a web application that requires storing user information, images, etc as well as storing status updates or posts/comments would I want to separate tables?
For example if I have a "users" table that contains users information like passwords, emails, and typical social networking info like age, location etc. Would it be a good idea do create a second table("posts") that handles user content such as comments and/or post?
Table one: "users"
UserID
Username
Age
etc.
Table Two: "posts"
PostID
PostContent
PostAuthor
PostDate
etc
Is this a valid organization? Furthermore if I wanted to keep track of media should I do this in ANOTHER table?
Table Three: "media"
ID
Type
Uploader
etc.
Any help is much appreciated. I'm curious to see if I'm on the right track or just completely lost. I am mostly wondering if I should have many tables or if I should have larger less segregated tables.
Also of note thus far I planned on keeping information such as followers(or friends) in the 'users' table but I'm not sure that's a good idea in retrospect.
thanks in advance,
Generally speaking to design a database you create a table for each object you will be dealing with. In you example you have Users, Posts, Comments and Media. From that you can flesh out what it is you want to store for each object. Each item you want to store is a field in the table:
[Users]
ID
Username
PasswordHash
Age
Birthdate
Email
JoinDate
LastLogin
[Posts]
ID
UserID
Title
Content
CreateDate
PostedDate
[Comments]
ID
PostID
UserID
Content
[Media]
ID
Title
Description
FileURI
Taking a look above you can see a basic structure for holding the information for each object. By the field names you can even tell the relationships between the objects. That is a post has a UserID so the post was created by that user. the comments have a PostID and a UserID so you can see that a comment was written by a person for a specific post.
Once you have the general fields identified you can look at some other aspects of the design. For example right now the Email field under the Users table means that a user can have one (1) email address, no more. You can solve this one of two ways... add more email fields (EmailA, EmailB, EmailC) this generally works if you know there are specific types of emails you are dealing with, for example EmailWork or EmailHome. This doesn't work if you do not know how many emails in total there will be. To solve this you can pull the emails out into its own table:
[Users]
ID
Username
PasswordHash
Age
Birthdate
JoinDate
LastLogin
[Emails]
ID
UserID
Email
Now you can have any number of emails for a single user. You can do this for just about any database you are trying to design. Take it in small steps and break your bigger objects into smaller ones as needed.
Update
To deal with friends you should think about the relationship you are dealing with. There is one (1) person with many friends. In relation to the tables above its one User to many Users. This can be done with a special table that hold no information other than the relationship you are looking for.
[Friends]
[UserA]
[UserB]
So if the current user's ID is in A his friend's ID is in B and visa-verse. This sets up the friendship so that if you are my friend, then I am your friend. There is no way for me to be your friend without you being mine. If you want to setup the ability for one way friendships you can setup the table like this:
[Friends]
[UserID]
[FriendID]
So If we are both friends with each other there would have to be 2 records, one for my friendship to you and one for your freindship to me.
You need to use multiple tables.
The amount of tables depends on how complex you want your interactive site to be. Based on what you have posted you would need a table that would store information about the users, a table for comments, and more such as a table to store status types.
For example tbl_Users should store:
1. UserID
2. First Name
3. Last name
4. Email
5. Password (encrypted)
6. Address
7. City
8. State
9. Country
10. Date of Birth
11. UserStatus
12. Etc
This project sounds like it should be using a relational DB that will pull up records, such as comments, by relative userIDs.
This means that you will need a table that stores the following:
1. CommentID (primary key, int, auto-increment)
2. Comment (text)
3. UserID (foreign key, int)
The comment is attached to a user through a foreign key, which is essentially the userId from the tbl_Users table. You would need to combine these tables in an SQL statement with your script to query the information as a single piece of information. See example code
$sql_userWall = "SELECT tbl_Users.*, tbl_Comments.*, tbl_userStatus FROM tbl_Users
INNER JOIN tbl_Comments ON tbl_Users.userID = tbl_Comments.userID
INNER JOIN tbl_UserStatus ON tbl_Users.userID = tbl.UserStatus
WHERE tbl_Users.userID = $userID";
This statement essentially says get the information of the provided user from the users table and also get all the comments with that has the same userID attached to it, and get the userStatus from the table of user status'.
Therefore you would need a table called tbl_userStatus that held unique statusIDs (primary key, int, auto-incrementing) along with a text (varchar) of a determined length that may say for example "online" or "offline". When you started the write the info out from e record using php, asp or a similar language the table will automatically retrieve the information from tbl_userStatus for you just by using a simple line like
<?php echo $_REQUEST['userStatus']; ?>
No extra work necessary. Most of your project time will be spent developing the DB structure and writing SQL statements that correctly retrieve the info you want for each page.
There are many great YouTube video series that describe relational DBS and drawing entity relational diagrams. This is what you should look into for learning more on creating the tye of project you were describing.
One last note, if you wanted comments to be visible for all members of a group this would describe what is known as a many-to-many relationship which would require additional tables to allow for multiple users to 'own' a relationship to a single table. You could store a single groupID that referred to a table of groups.
tbl_groups
1. GroupID
2. GroupName
3. More group info, etc
And a table of users registered for the group
Tbl_groupMembers
1. membershipCountID (primary key, int, auto-increment)
2. GroupID (foriegn key, int)
3. UserID (foriegn key, int)
This allows users to registrar for a group and inner join them to group based comments. These relationships take a little more time to understand, the videos will help greatly.
I hope this helps, I'll come back and post some YouTube links later that I found helpful learning this stuff.
Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 14 years ago.
Improve this question
We frequently have users that create multiple accounts and then end up storing the same lesson activity data more than once. Once they realize the error, then they contact us to merge the accounts into a single one that they can use.
I've been beating myself to death trying to figure out how to write a query in MySQL that will merge their activity logs into a single profile so that I can then delete the other profiles, but I still can't find the query that will work.
The tables look like this:
CREATE TABLE user_rtab (
user_id int PRIMARY KEY,
username varchar,
last_name varchar,
first_name varchar
);
CREATE TABLE lessonstatus_rtab (
lesson_id int,
user_id int,
accessdate timestamp,
score double,
);
What happens is that a user ends up taking the same lessons and also different lessons under two or more accounts and then they want to take all of their lesson statuses and have them assigned under one user account.
Can anyone provide a query that would accomplish this based on the lastname and firstname fields from the user table to determine all user accounts and then use only the user or username field to migrate all necessary statuses to the one single account?
Attempting to merge this data via last/first is a horrible idea, the more users you have, the more likely you are to mesh up incorrect entries. You have IDs on your tables for a reason, use them.
I don't see any reason why you can't say "I want to merge user 7 into 12" and then do the following:
UPDATE lessonstatus_rtab SET user_id=12 WHERE user_id=7;
DELETE FROM user_rtab WHERE user_id=7;
One of my current clients is facing a similar problem, except that they have dozens of tables that have to be merged. This is one reason to use a real life primary key (natural key). Your best bet is to try to avoid this problem before it even happens.
Another thing to keep in mind, is that two people can share both the same first and last name. Maybe you don't consider this an issue because of your user base, but if they're already creating multiple accounts how long is it until they start making up fake names or creating names that are almost the same, but not quite. Names are generally not a great thing to match on to determine if two people are the same or not.
As to the technical part of your question, it depends a lot on what the business rules are. If they have the same lesson in there twice with different scores do you use the highest score? How do you decide to which user account to link everything? No matter what, it's going to probably be a multi-step process.
How about this, assuming we are merging user_id 2 into 1.
This updates the lessons done under 2 that have not been done under 1.
UPDATE lessonstatus_rtab
SET user_id = 1
WHERE user_id = 2
AND NOT EXISTS
(SELECT *
FROM lessonstatus_rtab e
WHERE e.lesson_id = lessonstatus_rtab.lesson_id
AND user_id = 1)
Anything leftover is a duplicate and can now be removed:
DELETE FROM lessonstatus_rtab
WHERE user_id = 2