Reputation: 915
I'm creating tables for my site using the following design(s)
Design 1
Design 2
Since not every user who register will try the challenge, Design 1 is suited. On insert into third table, table 2 score is updated accordingly. But the user_id field becomes redundant.
Either 0 or NULL values are set for every user in design 2 which still isn't normalized. What would be the optimal design and how important is normalization or key in an organization?
Upvotes: 0
Views: 172
Reputation: 5911
Edit:
For future people - I had some problems understanding what OP was asking for so read through the comments if you get a little lost. Ultimately, they were looking to store aggregate data and didn't know where to put it or how to make it happen. The solution is basically to use an insert trigger, which is explained near the end of this post.
I chose to just add another column on to the user
table to store the accumulated sum of user_problem.score
. However, making a new table (with the columns user_id
and total_sum
) isn't a bad option at all even though it seems to be an excessive use of normalization. Sometimes it is good to keep data that is constantly updated separate from data that is rarely changed. That way if something goes wrong, you know your static data will be safe.
Something else I never touched on are the data concurrency and integrity issues associated with storing aggregate data in general... so beware of that.
I would suggest something like this:
User Table
User_ID - Email - Name - Password - FB_ID
-- holds all the user information
Problem Table
Problem_ID - Problem_Title - Problem_Descr
-- holds all the info on the individual challenges/problems/whatever
User_Problem Table
User_Problem_ID - User_ID - Problem_ID - Score - Completion_Date
-- Joins the User and Problem tables and has information specific
-- to a user+challenge pair
And this assumes that a user can take many challenges/problems. And one problem/challenge can be taken by several users.
To see all the problems by a certain user, you would do something like:
select user.user_id,
user.name,
problem_title,
problem_descr,
user_problem.score,
user_problem.completed_date
from user
join user_problem on user.user_id = user_problem.user_id
join problem on user_problem.problem_id = problem.problem_id
where user.user_id = 123 or user.email = '[email protected]'
The lengths for the varchar
fields are fairly generic...
create table User(
User_ID int unsigned auto_increment primary key,
Email varchar(100),
Name varchar(100),
Password varchar(100),
FB_ID int
);
create table Problem (
Problem_ID int unsigned auto_increment primary key,
Problem_Title varchar(100),
Problem_Descr varchar(500)
);
create table User_Problem (
User_Problem_ID int unsigned auto_increment primary key,
User_ID int unsigned,
Problem_ID int unsigned,
Score int,
Completion_Date datetime,
foreign key (User_ID) references User (User_ID),
foreign key (Problem_ID) references Problem (Problem_ID)
);
After our conversation from down below in the comments... you would add a column to user:
User Table
User_ID - Email - Name - Password - FB_ID - Total_Score
I gave the column a default value of 0 because you seemed to want/need that if the person didn't have any associated problem/challenges. Depending on other things, it may benefit you to make this an unsigned
int if you have a rule which states there will never be a negative score.
alter table user add column Total_Score int default 0;
then... you would use an insert trigger on the user_problem
table that affects the user
table.
CREATE TRIGGER tgr_update_total_score
AFTER INSERT ON User_Problem
FOR EACH ROW
UPDATE User
SET Total_score = Total_score + New.Score
WHERE User_ID = NEW.User_ID;
So... after a row is added to User_Problem
, you would add the new score to user.total_score
...
mysql> select * from user;
+---------+-------+------+----------+-------+-------------+
| User_ID | Email | Name | Password | FB_ID | Total_Score |
+---------+-------+------+----------+-------+-------------+
| 1 | NULL | kim | NULL | NULL | 0 |
| 2 | NULL | kyle | NULL | NULL | 0 |
+---------+-------+------+----------+-------+-------------+
2 rows in set (0.00 sec)
mysql> insert into user_problem values (null,1,1,10,now());
Query OK, 1 row affected (0.16 sec)
mysql> select * from user;
+---------+-------+------+----------+-------+-------------+
| User_ID | Email | Name | Password | FB_ID | Total_Score |
+---------+-------+------+----------+-------+-------------+
| 1 | NULL | kim | NULL | NULL | 10 |
| 2 | NULL | kyle | NULL | NULL | 0 |
+---------+-------+------+----------+-------+-------------+
2 rows in set (0.00 sec)
mysql> select * from user_problem;
+-----------------+---------+------------+-------+---------------------+
| User_Problem_ID | User_ID | Problem_ID | Score | Completion_Date |
+-----------------+---------+------------+-------+---------------------+
| 1 | 1 | 1 | 10 | 2013-11-03 11:31:53 |
+-----------------+---------+------------+-------+---------------------+
1 row in set (0.00 sec)
Upvotes: 2