Question

I'm creating tables for my site using the following design(s)

Design 1

enter image description here

Design 2

enter image description here

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?

Was it helpful?

Solution

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 = 'stuff@gmail.com'

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)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top